diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..59695180d6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,68 @@ + +[*.{appxmanifest,axml,build,c,c++,cc,cginc,compute,config,cp,cpp,csproj,cu,cuh,cxx,dbml,discomap,dtd,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,jsproj,lsproj,mpp,mq4,mq5,mqh,njsproj,nuspec,proj,props,proto,resw,resx,shader,StyleCop,targets,tasks,tpp,usf,ush,vbproj,xml,xsd}] +indent_style = space +indent_size = cs +tab_width = 4 + +[*.{asax,ascx,asmdef,aspx,axaml,cs,cshtml,css,htm,html,js,json,jsx,master,paml,razor,resjson,skin,ts,tsx,vb,xaml,xamlx,xoml}] +indent_style = space +indent_size = 4 +tab_width = 4 + +[*] + +# Microsoft .NET properties +csharp_new_line_before_members_in_object_initializers = false +csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion +csharp_style_var_elsewhere = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +dotnet_naming_rule.private_constants_rule.severity = warning +dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style +dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols +dotnet_naming_rule.private_instance_fields_rule.severity = warning +dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style +dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols +dotnet_naming_rule.private_static_fields_rule.severity = warning +dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style_1 +dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols +dotnet_naming_rule.private_static_readonly_rule.severity = warning +dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style +dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols +dotnet_naming_style.lower_camel_case_style.capitalization = camel_case +dotnet_naming_style.lower_camel_case_style_1.capitalization = camel_case +dotnet_naming_style.lower_camel_case_style_1.required_prefix = _ +dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case +dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field +dotnet_naming_symbols.private_constants_symbols.required_modifiers = const +dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static +dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion +dotnet_style_qualification_for_event = false:suggestion +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_property = false:suggestion + +# ReSharper properties +resharper_default_private_modifier = implicit + +# ReSharper inspection severities +resharper_arrange_redundant_parentheses_highlighting = hint +resharper_arrange_this_qualifier_highlighting = hint +resharper_built_in_type_reference_style_for_member_access_highlighting = hint +resharper_built_in_type_reference_style_highlighting = hint +resharper_redundant_base_qualifier_highlighting = warning +resharper_suggest_var_or_type_built_in_types_highlighting = hint +resharper_suggest_var_or_type_elsewhere_highlighting = hint +resharper_suggest_var_or_type_simple_types_highlighting = hint diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..9068a80499 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,33 @@ +* text=auto + +*.cs text eol=crlf + +*.h text eol=crlf +*.c text eol=crlf +*.cpp text eol=crlf + +*.as text eol=crlf +*.hx text eol=crlf + +*.sln text eol=crlf +*.csproj text eol=crlf +*.vbproj text eol=crlf +*.vcxproj text eol=crlf +*.vcproj text eol=crlf +*.dbproj text eol=crlf +*.fsproj text eol=crlf +*.lsproj text eol=crlf +*.wixproj text eol=crlf +*.modelproj text eol=crlf +*.sqlproj text eol=crlf +*.wmaproj text eol=crlf + +*.xproj text eol=crlf +*.props text eol=crlf +*.filters text eol=crlf +*.vcxitems text eol=crlf + +*.bat text eol=crlf +*.cmd text eol=crlf + +*.sh text eol=lf diff --git a/.gitignore b/.gitignore index de3726c816..c868e0da44 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,13 @@ Thumbs.db *.pdb *.suo *.user +*.vs/ *.vshost.exe *.vshost.exe.manifest -/.vs/ +**/obj/ +**/NSubstitute.* +**/nunit.framework.* +**/Castle.Core.* /FlashDevelop/Bin/Debug/Apps/ /FlashDevelop/Bin/Debug/Data/ /FlashDevelop/Bin/Debug/Plugins/ @@ -25,11 +29,11 @@ Thumbs.db /FlashDevelop/Bin/Debug/FlashDevelop64.* /FlashDevelop/Bin/Debug/PluginCore.* /FlashDevelop/Properties/AssemblyInfo.cs +/FlashDevelop/Scripting.* +/FlashDevelop/Bin/Debug/CSScriptLibrary.* +/FlashDevelop/Bin/Debug/Microsoft.* +/FlashDevelop/Bin/Debug/System.* +/FlashDevelop/Bin/Debug/Mono.* /packages/ /PluginCore/Bin -**/obj/ -**/NSubstitute.dll -**/NSubstitute.xml -**/nunit.framework.dll -**/nunit.framework.xml -.vs/ +FlashDevelop/Bin/Debug/LitJSON.* diff --git a/CI/build.cmd b/CI/build.cmd index 690b009797..da152e4c7b 100644 --- a/CI/build.cmd +++ b/CI/build.cmd @@ -1,18 +1,26 @@ :: Builds the binary on the server for CI :: Set paths -set PATH=%PATH%;C:\Windows\Microsoft.NET\Framework\v4.0.30319\ -set PATH=%PATH%;C:\Program Files (x86)\Git\bin\ -set PATH=%PATH%;C:\Program Files (x86)\NSIS -set PATH=%PATH%;C:\Program Files\7-Zip\ +:: set PATH=%PATH%;C:\Windows\Microsoft.NET\Framework\v4.0.30319\ +:: set PATH=%PATH%;C:\Program Files (x86)\Git\bin\ +:: set PATH=%PATH%;C:\Program Files (x86)\NSIS +:: set PATH=%PATH%;C:\Program Files\7-Zip\ :flashdevelop +:: Extract version from HEAD +call SetVersion.bat + +:: Build the main solution and run tests +msbuild FlashDevelop.sln /p:Configuration=Release+Tests /p:Platform="x64" /t:Rebuild %MSBuildLogger% + :: Check for build errors if %errorlevel% neq 0 goto :error -:: Extract version from HEAD -call SetVersion.bat +if "%AppVeyorCI%" neq "" powershell.exe -file ci\tests.ps1 + +:: Check for build errors +if %errorlevel% neq 0 goto :error :: Build the main solution and run tests msbuild FlashDevelop.sln /p:Configuration=Release+Tests /p:Platform="x86" /t:Rebuild %MSBuildLogger% @@ -25,24 +33,26 @@ if "%AppVeyorCI%" neq "" powershell.exe -file ci\tests.ps1 :: Check for build errors if %errorlevel% neq 0 goto :error -:: Remove testing binaries so we can reuse the current build -del "FlashDevelop\Bin/Debug\*.Tests.*" /Q -del "FlashDevelop\Bin/Debug\NSubstitute.*" /Q -del "FlashDevelop\Bin/Debug\nunit.framework.*" /Q +git clean -xfd FlashDevelop\Bin\Debug -:: Check if the build was triggered by a pull request -if "%APPVEYOR_PULL_REQUEST_NUMBER%" neq "" ( - :: Create the archive - 7z a -tzip FlashDevelop\Installer\Binary\FlashDevelopPR_%APPVEYOR_PULL_REQUEST_NUMBER%.zip .\FlashDevelop\Bin\Debug\* -xr!.empty - exit 0 -) +:: Extract version from HEAD +call SetVersion.bat + +nuget restore FlashDevelop.sln -:: Build AnyCPU version for 64bits support -msbuild FlashDevelop.sln /p:Configuration=Release /p:Platform="Any CPU" /t:Build %MSBuildLogger% +:: Build the solutions +msbuild FlashDevelop.sln /p:Configuration=Release /p:Platform="Any CPU" /t:Rebuild +ping -n 5 127.0.0.1 > nul +msbuild FlashDevelop.sln /p:Configuration=Release /p:Platform=x86 /t:Rebuild :: Check for build errors if %errorlevel% neq 0 goto :error +:: Remove files after build +del "FlashDevelop\Bin/Debug\System.*" /Q +del "FlashDevelop\Bin/Debug\Microsoft.*" /Q +del "FlashDevelop\Bin/Debug\Mono.CSharp.*" /Q + :: Create the installer makensis FlashDevelop\Installer\Installer.nsi @@ -58,7 +68,7 @@ if %errorlevel% neq 0 goto :error :haxedevelop :: Reset bin files -git clean -f -x -d FlashDevelop\Bin\Debug +git clean -xfd FlashDevelop\Bin\Debug :: Remove unnecessary files rd "FlashDevelop\Bin\Debug\Tools\flexpmd" /s /q @@ -83,15 +93,18 @@ msbuild FlashDevelop.sln /p:Configuration=Release /p:Platform=x86 /t:Rebuild :: Check for build errors if %errorlevel% neq 0 goto :error +:: Remove files after build +del "FlashDevelop\Bin\Debug\Plugins\CodeAnalyzer.dll" /q +del "FlashDevelop\Bin/Debug\System.*" /Q +del "FlashDevelop\Bin/Debug\Microsoft.*" /Q +del "FlashDevelop\Bin/Debug\Mono.CSharp.*" /Q + :: Rename binaries ren FlashDevelop\Bin\Debug\FlashDevelop.exe HaxeDevelop.exe ren FlashDevelop\Bin\Debug\FlashDevelop64.exe HaxeDevelop64.exe ren FlashDevelop\Bin\Debug\FlashDevelop.exe.config HaxeDevelop.exe.config ren FlashDevelop\Bin\Debug\FlashDevelop64.exe.config HaxeDevelop64.exe.config -: Remove files after build -del "FlashDevelop\Bin\Debug\Plugins\CodeAnalyzer.dll" /q - :: Check for build errors if %errorlevel% neq 0 goto :error @@ -108,4 +121,4 @@ if %errorlevel% neq 0 goto :error exit 0 :error -exit -1 +exit -1 \ No newline at end of file diff --git a/CI/buildl.cmd b/CI/buildl.cmd index a87170e81a..877a1a6ada 100644 --- a/CI/buildl.cmd +++ b/CI/buildl.cmd @@ -1,13 +1,14 @@ :: Builds the binary locally and launches the installer :: Set paths -set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin\ -set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin -set PATH=%PATH%;C:\Program Files\Git\bin\ -set PATH=%PATH%;C:\Program Files (x86)\Git\bin\ -set PATH=%PATH%;C:\Program Files\7-Zip\ -set PATH=%PATH%;C:\Program Files (x86)\7-Zip\ -set PATH=%PATH%;C:\Program Files (x86)\NSIS +:: set PATH=%PATH%;C:\Program Files (x86)\MSBuild\15.0\Bin\ +:: set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin +:: set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\Bin +:: set PATH=%PATH%;C:\Program Files\Git\bin\ +:: set PATH=%PATH%;C:\Program Files (x86)\Git\bin\ +:: set PATH=%PATH%;C:\Program Files\7-Zip\ +:: set PATH=%PATH%;C:\Program Files (x86)\7-Zip\ +:: set PATH=%PATH%;C:\Program Files (x86)\NSIS :: Need path up cd .. diff --git a/CI/tests.ps1 b/CI/tests.ps1 index 9f46fbdb7e..047c27f0db 100644 --- a/CI/tests.ps1 +++ b/CI/tests.ps1 @@ -14,36 +14,44 @@ Param ( If ($env:HAXEPATH -eq $null) { - cinst.exe haxe --version 3.4.3 -y - $env:HAXEPATH = "c:\ProgramData\chocolatey\lib\haxe\" - RefreshEnv + cinst.exe haxe --version 4.1.4 -y --no-progress + $env:HAXEPATH = [System.IO.Directory]::GetDirectories("C:\ProgramData\chocolatey\lib\haxe", "haxe_*")[0]; + If ($env:HAXEPATH -eq $null) + { + Write-Output "HAXEPATH is invalid" + exit 1 + } } -If ((Get-Command "nunit-console-x86.exe" -ErrorAction SilentlyContinue) -ne $null) +If ((Get-Command "nunit3-console.exe" -ErrorAction SilentlyContinue) -ne $null) { - $testFiles = [System.IO.Directory]::GetFiles("FlashDevelop\Bin\Debug", "*.Tests.dll") + $path = [System.IO.Directory]::GetCurrentDirectory() + "\FlashDevelop\Bin\Debug" + $testFiles = [System.IO.Directory]::GetFiles($path, "*.Tests.dll") IF ($testFiles.Count -eq 0) { Write-Output "No test assemblies found" + exit 1 } - ELSE - { - #Maybe in the future we want to set categories and priorities - nunit-console-x86.exe $testFiles - #It turns out it's not needed to upload the file - #if ((Test-Path env:\APPVEYOR_JOB_ID) -And (Test-Path TestResult.xml)) - #{ - # $wc = New-Object 'System.Net.WebClient' - # $wc.UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestResult.xml)) - #} + + cd $path + #nunit3-console.exe $testFiles --result=myresults.xml;format=AppVeyor + #nunit3-console.exe $testFiles --x86 + nunit3-console.exe $testFiles + + #It turns out it's not needed to upload the file + #if ((Test-Path env:\APPVEYOR_JOB_ID) -And (Test-Path TestResult.xml)) + #{ + # $wc = New-Object 'System.Net.WebClient' + # $wc.UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestResult.xml)) + #} - if ($LASTEXITCODE -ne 0) - { - exit 1 - } + if ($LASTEXITCODE -ne 0) + { + exit 1 } } ELSE { Write-Output "NUnit runner not found" -} + exit 1 +} \ No newline at end of file diff --git a/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/Docs/index.html b/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/Docs/index.html index 15faceefa0..40c76b8a41 100644 --- a/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/Docs/index.html +++ b/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/Docs/index.html @@ -20,7 +20,7 @@

Description

based languages. Altought the program is designed mostly for Haxe, other languages can be implemented quite easily too. HaxeDevelop requires the Microsoft.NET 4.0 Framework. You can support us by donating for the project via PayPal. Any donation, even 1$, is good for the project. Code contributions are also welcome.

-

You can find more info about HaxeDevelop from the project website www.haxedevelop.org. +

You can find more info about HaxeDevelop from the project website haxedevelop.org.

HaxeDevelop is a custom distribution of FlashDevelop.

@@ -54,7 +54,7 @@

Components

Licence

-

Copyright (c) 2017 Haxe Foundation - HaxeDevelop.org

+

Copyright (c) 2018 Haxe Foundation - HaxeDevelop.org

Portions copyright Mika Palmu, Philippe Elsass and all helpful contributors.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation diff --git a/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/StartPage/javascript/startpage.js b/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/StartPage/javascript/startpage.js index 69f6ebb18e..686ad54df1 100644 --- a/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/StartPage/javascript/startpage.js +++ b/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/StartPage/javascript/startpage.js @@ -188,7 +188,7 @@ function handleXmlData(projectXml, rssUrl) { if (rssUrl != null) { - var hdUrl = "http://www.haxedevelop.org/latest.txt"; + var hdUrl = "https://haxedevelop.org/latest.txt"; loadTextDocument(hdUrl, handleVersionInfo); loadTextDocument(rssUrl, handleRssFeedXml); } diff --git a/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/Tools/winres/winres.exe b/Distros/HaxeDevelop/FlashDevelop/Bin/Debug/Tools/winres/winres.exe old mode 100644 new mode 100755 diff --git a/Distros/HaxeDevelop/FlashDevelop/Installer/Config.nsh b/Distros/HaxeDevelop/FlashDevelop/Installer/Config.nsh index 36e4bdde2f..2f2f8b634e 100644 --- a/Distros/HaxeDevelop/FlashDevelop/Installer/Config.nsh +++ b/Distros/HaxeDevelop/FlashDevelop/Installer/Config.nsh @@ -1,7 +1,7 @@ ; Define distro config !define DIST_NAME "HaxeDevelop" !define DIST_COMP "HaxeDevelop.org" -!define DIST_COPY "HaxeDevelop.org 2005-2016" -!define DIST_README "http://www.haxedevelop.org" -!define DIST_COMMUNITY "http://www.haxedevelop.org/community/" -!define DIST_DOCS "http://www.haxedevelop.org"; +!define DIST_COPY "HaxeDevelop.org 2005-2018" +!define DIST_README "http://haxedevelop.org" +!define DIST_COMMUNITY "https://haxedevelop.org/blog/" +!define DIST_DOCS "https://haxedevelop.org"; diff --git a/Distros/HaxeDevelop/PluginCore/PluginCore/DistroConfig.cs b/Distros/HaxeDevelop/PluginCore/PluginCore/DistroConfig.cs index 312d14c4bc..5cd871dd5e 100644 --- a/Distros/HaxeDevelop/PluginCore/PluginCore/DistroConfig.cs +++ b/Distros/HaxeDevelop/PluginCore/PluginCore/DistroConfig.cs @@ -4,16 +4,17 @@ namespace PluginCore { public class DistroConfig { - public const String DISTRIBUTION_NAME = "HaxeDevelop"; - public const String DISTRIBUTION_DESC = "HaxeDevelop is an open source script editor."; - public const String DISTRIBUTION_HOME = "http://www.haxedevelop.org/"; - public const String DISTRIBUTION_HELP = "http://haxedevelop.org/system-requirements.html"; - public const String DISTRIBUTION_VERSION = "http://www.haxedevelop.org/latest.txt"; - public const String DISTRIBUTION_ABOUT = "HaxeDevelop logo, domain and the name are copyright of Haxe Foundation.\r\nHaxeDevelop is a custom distribution of FlashDevelop.\r\nDevelopment: Mika Palmu, Philippe Elsass and all helpful contributors."; - public const String DISTRIBUTION_COPYRIGHT = "HaxeDevelop.org 2015-2017"; - public const String DISTRIBUTION_COMPANY = "HaxeDevelop.org"; - public const String DISTRIBUTION_RSS = "http://www.haxedevelop.org/rss.xml"; - public const String DISTRIBUTION_EXT = "hx"; + public const string DISTRIBUTION_NAME = "HaxeDevelop"; + public const string DISTRIBUTION_DESC = "HaxeDevelop is an open source script editor."; + public const string DISTRIBUTION_HOME = "https://haxedevelop.org/"; + public const string DISTRIBUTION_HELP = "https://haxedevelop.org/system-requirements.html"; + public const string DISTRIBUTION_VERSION = "https://haxedevelop.org/latest.txt"; + public const string DISTRIBUTION_ABOUT = "HaxeDevelop logo, domain and the name are copyright of Haxe Foundation.\r\nHaxeDevelop is a custom distribution of FlashDevelop.\r\nDevelopment: Mika Palmu, Philippe Elsass and all helpful contributors."; + public const string DISTRIBUTION_COPYRIGHT = "HaxeDevelop.org 2015-2020"; + public const string DISTRIBUTION_COMPANY = "HaxeDevelop.org"; + public const string DISTRIBUTION_RSS = "https://haxedevelop.org/rss.xml"; + public const string DISTRIBUTION_EXT = "hx"; + public const string DISTRIBUTION_DEV_VERSION = "https://flashdevelop.org/downloads/builds/HaxeDevelop-development.txt"; + public const string DISTRIBUTION_DEV_BUILD = "https://flashdevelop.org/downloads/builds/HaxeDevelop-development.exe"; } - -} +} \ No newline at end of file diff --git a/Distros/README.md b/Distros/README.md index 684e27f7d7..5287a78ecd 100644 --- a/Distros/README.md +++ b/Distros/README.md @@ -1 +1,7 @@ -Coming soon... +# FlashDevelop distros + +## Haxedevelop + +HaxeDevelop a custom distribution of FlashDevelop where editor configuration is focussed on [Haxe](https://haxe.org/). + +* More info: diff --git a/External/3rdParty/Aga-1.7/Aga.Controls/Aga.Controls.csproj b/External/3rdParty/Aga-1.7/Aga.Controls/Aga.Controls.csproj index ee369c5fa1..de5b13bbf6 100644 --- a/External/3rdParty/Aga-1.7/Aga.Controls/Aga.Controls.csproj +++ b/External/3rdParty/Aga-1.7/Aga.Controls/Aga.Controls.csproj @@ -1,10 +1,8 @@  - + Debug AnyCPU - 9.0.30729 - 2.0 {E73BB233-D88B-44A7-A98F-D71EE158381D} Library Properties @@ -22,10 +20,13 @@ key.snk - 3.5 - v4.0 + net48 + true + false + false + false @@ -238,12 +239,4 @@ - - \ No newline at end of file diff --git a/External/3rdParty/Duplicate/Duplicate.csproj b/External/3rdParty/Duplicate/Duplicate.csproj index 8ac191a7aa..38a487b43e 100644 --- a/External/3rdParty/Duplicate/Duplicate.csproj +++ b/External/3rdParty/Duplicate/Duplicate.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 9.0.30729 - 2.0 {7AF50A69-26D3-400B-9DFF-96CB36E1A871} Library Properties @@ -14,8 +12,11 @@ - 2.0 - v2.0 + net48 + true + false + false + false @@ -50,14 +51,6 @@ TRACE true - - False diff --git a/External/3rdParty/Trace/Trace.csproj b/External/3rdParty/Trace/Trace.csproj index d337957805..831f7aa5a3 100644 --- a/External/3rdParty/Trace/Trace.csproj +++ b/External/3rdParty/Trace/Trace.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 9.0.30729 - 2.0 {78101C01-E186-4954-B1DD-DEBB7905FAD8} Library Properties @@ -14,8 +12,11 @@ - 2.0 - v2.0 + net48 + true + false + false + false @@ -65,14 +66,6 @@ TRACE true - - False diff --git a/External/Archive/FlashDebugger/FlashDebugger.csproj b/External/Archive/FlashDebugger/FlashDebugger.csproj index 3cddc7eaa8..27731fd483 100644 --- a/External/Archive/FlashDebugger/FlashDebugger.csproj +++ b/External/Archive/FlashDebugger/FlashDebugger.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 9.0.30729 - 2.0 {194B58C9-9D2B-4D5E-9256-773FD3222582} Library Properties @@ -14,8 +12,11 @@ - 2.0 - v2.0 + net48 + true + false + false + false @@ -49,14 +50,6 @@ TRACE true - - False diff --git a/External/Archive/FlashDebugger/FlexSDK/SwfUtils/flash/swf/NotUsed/TagEncoder.cs b/External/Archive/FlashDebugger/FlexSDK/SwfUtils/flash/swf/NotUsed/TagEncoder.cs index f73290ca23..61fa2ef8cb 100644 --- a/External/Archive/FlashDebugger/FlexSDK/SwfUtils/flash/swf/NotUsed/TagEncoder.cs +++ b/External/Archive/FlashDebugger/FlexSDK/SwfUtils/flash/swf/NotUsed/TagEncoder.cs @@ -1,2314 +1,2314 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// ADOBE SYSTEMS INCORPORATED -// Copyright 2003-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file -// in accordance with the terms of the license agreement accompanying it. -// -//////////////////////////////////////////////////////////////////////////////// -using System; -using flash.swf.tags; -using ButtonCondAction = flash.swf.types.ButtonCondAction; -using ButtonRecord = flash.swf.types.ButtonRecord; -using CXForm = flash.swf.types.CXForm; -using CXFormWithAlpha = flash.swf.types.CXFormWithAlpha; -using CurvedEdgeRecord = flash.swf.types.CurvedEdgeRecord; -using EdgeRecord = flash.swf.types.EdgeRecord; -using FillStyle = flash.swf.types.FillStyle; -using GlyphEntry = flash.swf.types.GlyphEntry; -using GradRecord = flash.swf.types.GradRecord; -using ImportRecord = flash.swf.types.ImportRecord; -using KerningRecord = flash.swf.types.KerningRecord; -using LineStyle = flash.swf.types.LineStyle; -using MD5 = flash.swf.types.MD5; -using Matrix = flash.swf.types.Matrix; -using MorphFillStyle = flash.swf.types.MorphFillStyle; -using MorphGradRecord = flash.swf.types.MorphGradRecord; -using MorphLineStyle = flash.swf.types.MorphLineStyle; -using Rect = flash.swf.types.Rect; -using Shape = flash.swf.types.Shape; -using ShapeRecord = flash.swf.types.ShapeRecord; -using ShapeWithStyle = flash.swf.types.ShapeWithStyle; -using SoundInfo = flash.swf.types.SoundInfo; -using StraightEdgeRecord = flash.swf.types.StraightEdgeRecord; -using StyleChangeRecord = flash.swf.types.StyleChangeRecord; -using TextRecord = flash.swf.types.TextRecord; -using Filter = flash.swf.types.Filter; -using DropShadowFilter = flash.swf.types.DropShadowFilter; -using BlurFilter = flash.swf.types.BlurFilter; -using ColorMatrixFilter = flash.swf.types.ColorMatrixFilter; -using GlowFilter = flash.swf.types.GlowFilter; -using ConvolutionFilter = flash.swf.types.ConvolutionFilter; -using BevelFilter = flash.swf.types.BevelFilter; -using GradientGlowFilter = flash.swf.types.GradientGlowFilter; -using GradientBevelFilter = flash.swf.types.GradientBevelFilter; -using Gradient = flash.swf.types.Gradient; -using FocalGradient = flash.swf.types.FocalGradient; -namespace flash.swf -{ - - public class TagEncoder:TagHandler, TagValues - { - virtual public int Pos - { - get - { - return writer.Pos; - } - - } - virtual protected internal int SwfVersion - { - get - { - return header_Renamed_Field.version; - } - - } - virtual protected internal int FrameRate - { - get - { - return header_Renamed_Field.rate; - } - - } - virtual public Dictionary EncoderDictionary - { - set - { - assert((this.dict == null) || (this.dict.ids.Count == 0)); - this.dict = value; - } - - } - virtual public Dictionary Dictionary - { - get - { - return dict; - } - - } - virtual public bool Debug - { - get - { - return debug != null; - } - - } - virtual public int Width - { - get - { - return width / 20; - } - - } - virtual public int Height - { - get - { - return height / 20; - } - - } - virtual public System.String MainDebugScript - { - set - { - debug.MainDebugScript = value; - } - - } - override public SetBackgroundColor BackgroundColor - { - set - { - encodeTagHeader(value.code, 3, false); - encodeRGB(value.color, writer); - } - - } - override public SetTabIndex TabIndex - { - set - { - tagw.writeUI16(value.depth); - tagw.writeUI16(value.index); - encodeTag(value); - } - - } - // changed from private to protected to support Flash Authoring - jkamerer 2007.07.30 - protected internal SwfEncoder writer; - private SwfEncoder tagw; - private int width; - private int height; - private int frames; - private int framecountPos; - private DebugEncoder debug; - private Header header_Renamed_Field; - - protected internal Dictionary dict; - private int uuidOffset; - - public TagEncoder() - { - dict = new Dictionary(); - } - - public TagEncoder(Dictionary dict) - { - this.dict = dict; - } - - public override void productInfo(ProductInfo tag) - { - tagw.write32(tag.Product); - tagw.write32(tag.Edition); - tagw.write(new sbyte[]{tag.MajorVersion, tag.MinorVersion}); - tagw.write64(tag.Build); - tagw.write64(tag.CompileDate); - encodeTag(tag); - } - - public override void fileAttributes(FileAttributes tag) - { - tagw.writeUBits(0, 3); - tagw.writeBit(tag.hasMetadata); - tagw.writeBit(tag.actionScript3); - tagw.writeBit(tag.suppressCrossDomainCaching); - tagw.writeBit(tag.swfRelativeUrls); - tagw.writeBit(tag.useNetwork); - tagw.writeUBits(0, 24); - encodeTag(tag); - } - - public override void metadata(Metadata tag) - { - tagw.writeString(tag.xml); - encodeTag(tag); - } - - protected internal virtual SwfEncoder createEncoder(int swfVersion) - { - return new SwfEncoder(swfVersion); - } - - public override void header(Header header) - { - // get some header properties we need to know - int swfVersion = header.version; - this.header_Renamed_Field = header; - this.writer = createEncoder(swfVersion); - this.tagw = createEncoder(swfVersion); - width = header.size.Width; - height = header.size.Height; - frames = 0; - - // write the header - writer.writeUI8(header.compressed?'C':'F'); - writer.writeUI8('W'); - writer.writeUI8('S'); - writer.writeUI8(header.version); - writer.write32((int) header.length); - if (header.compressed) - { - writer.markComp(); - } - encodeRect(header.size, writer); - writer.writeUI8(header.rate >> 8); - writer.writeUI8(header.rate & 255); - framecountPos = writer.Pos; - writer.writeUI16(header.framecount); - } - - public override void finish() - { - // write end marker - writer.writeUI16(0); - - // update the length - writer.write32at(4, writer.Pos); - - // update the frame count - writer.writeUI16at(framecountPos, frames); - - if (debug != null) - { - // compute a crc and use it for the debug id. that way it - // is wholly dependent on the bytes in the SWF and not some - // outside value. If any of the bytes are different, - // then the UUID will be different. - sbyte[] md5 = MD5.getDigest(writer.ByteArray, writer.Length); - writer.writeAt(uuidOffset, md5); - debug.updateUUID(md5); - } - } - - public virtual void writeTo(System.IO.Stream out_Renamed) - { - writer.WriteTo(out_Renamed); - } - - - public virtual void writeDebugTo(System.IO.Stream out_Renamed) - { - debug.writeTo(out_Renamed); - } - - public virtual void encodeRect(Rect r, SwfEncoder w) - { - int nBits = r.nbits(); - w.writeUBits(nBits, 5); - w.writeSBits(r.xMin, nBits); - w.writeSBits(r.xMax, nBits); - w.writeSBits(r.yMin, nBits); - w.writeSBits(r.yMax, nBits); - w.flushBits(); - } - - public override void debugID(DebugID tag) - { - encodeTagHeader(tag.code, tag.uuid.bytes.Length, false); - uuidOffset = writer.Pos; - writer.write(tag.uuid.bytes); - - debug = new DebugEncoder(); - debug.header(SwfVersion); - debug.uuid(tag.uuid); - } - - private void encodeTag(Tag tag) - { - try - { - tagw.compress(); - encodeTagHeader(tag.code, tagw.Pos, isLongHeader(tag)); - tagw.WriteTo(writer); - tagw.reset(); - } - catch (System.IO.IOException e) - { - assert(false); - } - } - - private bool isLongHeader(Tag t) - { - switch (t.code) - { - - // [preilly] In the player code, ScriptThread::DefineBits() assumes all DefineBits - // tags use a long header. See "ch->data = AttachData(pos-8);". If the player - // also supported a short header, it would use "pos-4". - case flash.swf.TagValues_Fields.stagDefineBits: - case flash.swf.TagValues_Fields.stagDefineBitsJPEG2: - case flash.swf.TagValues_Fields.stagDefineBitsJPEG3: - case flash.swf.TagValues_Fields.stagDefineBitsLossless: - case flash.swf.TagValues_Fields.stagDefineBitsLossless2: - return true; - - // [ed] the FlashPaper codebase also indicates that stagSoundStreamBlock must use - // a long format header. todo - verify by looking at the player code. - - case flash.swf.TagValues_Fields.stagSoundStreamBlock: - return true; - - // [edsmith] these tags have code in them. When we're writing a SWD, we use long headers - // so we can predict SWF offsets correctly when writing SWD line/offset records. - - case flash.swf.TagValues_Fields.stagDefineButton: - case flash.swf.TagValues_Fields.stagDefineButton2: - case flash.swf.TagValues_Fields.stagDefineSprite: - case flash.swf.TagValues_Fields.stagDoInitAction: - case flash.swf.TagValues_Fields.stagDoAction: - return Debug; - - - case flash.swf.TagValues_Fields.stagPlaceObject2: - return Debug && ((PlaceObject) t).hasClipAction(); - - // all other tags will use short/long headers depending on their length - - default: - return false; - - } - } - - private void encodeTagHeader(int code, int length, bool longHeader) - { - if (longHeader || length >= 63) - { - writer.writeUI16((code << 6) | 63); - writer.write32(length); - } - else - { - writer.writeUI16((code << 6) | length); - } - } - - public override void defineScalingGrid(DefineScalingGrid tag) - { - int idref = dict.getId(tag.scalingTarget); - tagw.writeUI16(idref); - encodeRect(tag.rect, tagw); - encodeTag(tag); - } - - public override void defineBinaryData(DefineBinaryData tag) - { - encodeTagHeader(tag.code, 6 + tag.data.Length, false); - int id = dict.add(tag); - writer.writeUI16(id); - writer.write32(tag.reserved); - writer.write(tag.data); - } - - public override void defineBits(DefineBits tag) - { - encodeTagHeader(tag.code, 2 + tag.data.Length, true); - int id = dict.add(tag); - writer.writeUI16(id); - writer.write(tag.data); - } - - public override void defineBitsJPEG2(DefineBits tag) - { - defineBits(tag); - } - - public override void defineBitsJPEG3(DefineBitsJPEG3 tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - tagw.write32(tag.data.Length); - tagw.write(tag.data); - tagw.markComp(); - tagw.write(tag.alphaData); - encodeTag(tag); - } - - public override void defineBitsLossless(DefineBitsLossless tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - tagw.writeUI8(tag.format); - tagw.writeUI16(tag.width); - tagw.writeUI16(tag.height); - switch (tag.format) - { - - case 3: - tagw.writeUI8(tag.colorData.Length - 1); - tagw.markComp(); - encodeColorMapData(tag.colorData, tag.data, tagw); - break; - - case 4: - case 5: - tagw.markComp(); - encodeBitmapData(tag.data, tagw); - break; - } - encodeTag(tag); - } - - private void encodeBitmapData(sbyte[] data, SwfEncoder w) - { - w.write(data); - } - - private void encodeColorMapData(int[] colorData, sbyte[] pixelData, SwfEncoder w) - { - for (int i = 0; i < colorData.Length; i++) - { - encodeRGB(colorData[i], w); - } - w.write(pixelData); - } - - /// as 0x00RRGGBB - /// - /// - /// - private void encodeRGB(int rgb, SwfEncoder w) - { - w.writeUI8(SupportClass.URShift(rgb, 16)); // red. we don't mask this because if rgb has an Alpha value, something's wrong - w.writeUI8((SupportClass.URShift(rgb, 8)) & 255); - w.writeUI8(rgb & 255); // blue - } - - public override void defineBitsLossless2(DefineBitsLossless tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - tagw.writeUI8(tag.format); - tagw.writeUI16(tag.width); - tagw.writeUI16(tag.height); - switch (tag.format) - { - - case 3: - tagw.writeUI8(tag.colorData.Length - 1); - tagw.markComp(); - encodeAlphaColorMapData(tag.colorData, tag.data, tagw); - break; - - case 4: - case 5: - tagw.markComp(); - encodeBitmapData(tag.data, tagw); - break; - } - encodeTag(tag); - } - - private void encodeAlphaColorMapData(int[] colorData, sbyte[] pixelData, SwfEncoder w) - { - for (int i = 0; i < colorData.Length; i++) - { - encodeRGBA(colorData[i], w); - } - w.write(pixelData); - } - - /// as 0xAARRGGBB - /// - /// - /// - private void encodeRGBA(int rgba, SwfEncoder w) - { - w.writeUI8((SupportClass.URShift(rgba, 16)) & 255); // red - w.writeUI8((SupportClass.URShift(rgba, 8)) & 255); // green - w.writeUI8(rgba & 255); // blue - w.writeUI8(SupportClass.URShift(rgba, 24)); // alpha - } - - public override void defineButton(DefineButton tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - - if (Debug) - { - debug.adjust = writer.Pos + 6; - } - - for (int i = 0; i < tag.buttonRecords.Length; i++) - { - encodeButtonRecord(tag.buttonRecords[i], tagw, tag.code); - } - tagw.writeUI8(0); // no more button records - - // assume there is only one condition we will handle - new ActionEncoder(tagw, debug).encode(tag.condActions[0].actionList); - tagw.writeUI8(0); // write action end flag, must be zero - encodeTag(tag); - - if (Debug) - { - debug.adjust = 0; - } - } - - private void encodeButtonRecord(ButtonRecord record, SwfEncoder w, int defineButton) - { - if (defineButton == flash.swf.TagValues_Fields.stagDefineButton2) - { - w.writeUBits(0, 2); - w.writeBit(record.blendMode != - 1); - w.writeBit(record.filters != null); - } - else - { - w.writeUBits(0, 4); - } - w.writeBit(record.hitTest); - w.writeBit(record.down); - w.writeBit(record.over); - w.writeBit(record.up); - - w.writeUI16(dict.getId(record.characterRef)); - w.writeUI16(record.placeDepth); - encodeMatrix(record.placeMatrix, w); - - if (defineButton == flash.swf.TagValues_Fields.stagDefineButton2) - { - encodeCxforma(record.colorTransform, w); - if (record.filters != null) - { - this.encodeFilterList(record.filters, w); - } - if (record.blendMode != - 1) - { - w.writeUI8(record.blendMode); - } - } - } - - private void encodeCxforma(CXFormWithAlpha cxforma, SwfEncoder w) - { - w.writeBit(cxforma.hasAdd); - w.writeBit(cxforma.hasMult); - - int nbits = cxforma.nbits(); - w.writeUBits(nbits, 4); - - if (cxforma.hasMult) - { - w.writeSBits(cxforma.redMultTerm, nbits); - w.writeSBits(cxforma.greenMultTerm, nbits); - w.writeSBits(cxforma.blueMultTerm, nbits); - w.writeSBits(cxforma.alphaMultTerm, nbits); - } - - if (cxforma.hasAdd) - { - w.writeSBits(cxforma.redAddTerm, nbits); - w.writeSBits(cxforma.greenAddTerm, nbits); - w.writeSBits(cxforma.blueAddTerm, nbits); - w.writeSBits(cxforma.alphaAddTerm, nbits); - } - - w.flushBits(); - } - - private void encodeMatrix(Matrix matrix, SwfEncoder w) - { - w.writeBit(matrix.hasScale); - if (matrix.hasScale) - { - int nScaleBits = matrix.nScaleBits(); - w.writeUBits(nScaleBits, 5); - w.writeSBits(matrix.scaleX, nScaleBits); - w.writeSBits(matrix.scaleY, nScaleBits); - } - - w.writeBit(matrix.hasRotate); - if (matrix.hasRotate) - { - int nRotateBits = matrix.nRotateBits(); - w.writeUBits(nRotateBits, 5); - w.writeSBits(matrix.rotateSkew0, nRotateBits); - w.writeSBits(matrix.rotateSkew1, nRotateBits); - } - - int nTranslateBits = matrix.nTranslateBits(); - w.writeUBits(nTranslateBits, 5); - w.writeSBits(matrix.translateX, nTranslateBits); - w.writeSBits(matrix.translateY, nTranslateBits); - - w.flushBits(); - } - - public override void defineButton2(DefineButton tag) - { - if (Debug) - { - debug.adjust = writer.Pos + 6; - } - - int id = dict.add(tag); - tagw.writeUI16(id); - tagw.writeUBits(0, 7); // reserved - tagw.writeBit(tag.trackAsMenu); - int offsetPos = tagw.Pos; - tagw.writeUI16(0); // actionOffset - - for (int i = 0; i < tag.buttonRecords.Length; i++) - { - encodeButtonRecord(tag.buttonRecords[i], tagw, tag.code); - } - - tagw.writeUI8(0); // charEndFlag - - if (tag.condActions.Length > 0) - { - tagw.writeUI16at(offsetPos, tagw.Pos - offsetPos); - - for (int i = 0; i < tag.condActions.Length; i++) - { - bool isLast = i + 1 == tag.condActions.Length; - encodeButtonCondAction(tag.condActions[i], tagw, isLast); - } - } - encodeTag(tag); - - if (Debug) - { - debug.adjust = 0; - } - } - - private void encodeButtonCondAction(ButtonCondAction condAction, SwfEncoder w, bool last) - { - int pos = w.Pos; - w.writeUI16(0); - - w.writeUBits(condAction.keyPress, 7); - w.writeBit(condAction.overDownToIdle); - - w.writeBit(condAction.idleToOverDown); - w.writeBit(condAction.outDownToIdle); - w.writeBit(condAction.outDownToOverDown); - w.writeBit(condAction.overDownToOutDown); - w.writeBit(condAction.overDownToOverUp); - w.writeBit(condAction.overUpToOverDown); - w.writeBit(condAction.overUpToIdle); - w.writeBit(condAction.idleToOverUp); - - new ActionEncoder(w, debug).encode(condAction.actionList); - w.writeUI8(0); // end action byte - - if (!last) - { - w.writeUI16at(pos, w.Pos - pos); - } - } - - public override void defineButtonCxform(DefineButtonCxform tag) - { - int idref = dict.getId(tag.button); - tagw.writeUI16(idref); - encodeCxform(tag.colorTransform, tagw); - encodeTag(tag); - } - - private void encodeCxform(CXForm cxform, SwfEncoder w) - { - - w.writeBit(cxform.hasAdd); - w.writeBit(cxform.hasMult); - - int nbits = cxform.nbits(); - w.writeUBits(nbits, 4); - - if (cxform.hasMult) - { - w.writeSBits(cxform.redMultTerm, nbits); - w.writeSBits(cxform.greenMultTerm, nbits); - w.writeSBits(cxform.blueMultTerm, nbits); - } - - if (cxform.hasAdd) - { - w.writeSBits(cxform.redAddTerm, nbits); - w.writeSBits(cxform.greenAddTerm, nbits); - w.writeSBits(cxform.blueAddTerm, nbits); - } - - w.flushBits(); - } - - public override void defineButtonSound(DefineButtonSound tag) - { - int idref = dict.getId(tag.button); - tagw.writeUI16(idref); - if (tag.sound0 != null) - { - tagw.writeUI16(dict.getId(tag.sound0)); - encodeSoundInfo(tag.info0, tagw); - } - else - { - tagw.writeUI16(0); - } - if (tag.sound1 != null) - { - tagw.writeUI16(dict.getId(tag.sound1)); - encodeSoundInfo(tag.info1, tagw); - } - else - { - tagw.writeUI16(0); - } - if (tag.sound2 != null) - { - tagw.writeUI16(dict.getId(tag.sound2)); - encodeSoundInfo(tag.info2, tagw); - } - else - { - tagw.writeUI16(0); - } - if (tag.sound3 != null) - { - tagw.writeUI16(dict.getId(tag.sound3)); - encodeSoundInfo(tag.info3, tagw); - } - else - { - tagw.writeUI16(0); - } - encodeTag(tag); - } - - private void encodeSoundInfo(SoundInfo info, SwfEncoder w) - { - w.writeUBits(0, 2); // reserved - w.writeBit(info.syncStop); - w.writeBit(info.syncNoMultiple); - w.writeBit(info.records != null); - w.writeBit(info.loopCount != SoundInfo.UNINITIALIZED); - w.writeBit(info.outPoint != SoundInfo.UNINITIALIZED); - w.writeBit(info.inPoint != SoundInfo.UNINITIALIZED); - - if (info.inPoint != SoundInfo.UNINITIALIZED) - { - w.write32((int) info.inPoint); - } - if (info.outPoint != SoundInfo.UNINITIALIZED) - { - w.write32((int) info.outPoint); - } - if (info.loopCount != SoundInfo.UNINITIALIZED) - { - w.writeUI16(info.loopCount); - } - if (info.records != null) - { - w.writeUI8(info.records.Length); - for (int k = 0; k < info.records.Length; k++) - { - w.write64(info.records[k]); - } - } - } - - public override void defineEditText(DefineEditText tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - encodeRect(tag.bounds, tagw); - - tagw.writeBit(tag.hasText); - tagw.writeBit(tag.wordWrap); - tagw.writeBit(tag.multiline); - tagw.writeBit(tag.password); - tagw.writeBit(tag.readOnly); - tagw.writeBit(tag.hasTextColor); - tagw.writeBit(tag.hasMaxLength); - tagw.writeBit(tag.hasFont); - - tagw.writeBit(false); // reserved - tagw.writeBit(tag.autoSize); - tagw.writeBit(tag.hasLayout); - tagw.writeBit(tag.noSelect); - tagw.writeBit(tag.border); - tagw.writeBit(tag.wasStatic); - tagw.writeBit(tag.html); - tagw.writeBit(tag.useOutlines); - - tagw.flushBits(); - - if (tag.hasFont) - { - int idref = dict.getId(tag.font); - tagw.writeUI16(idref); - tagw.writeUI16(tag.height); - } - - if (tag.hasTextColor) - { - encodeRGBA(tag.color, tagw); - } - - if (tag.hasMaxLength) - { - tagw.writeUI16(tag.maxLength); - } - - if (tag.hasLayout) - { - tagw.writeUI8(tag.align); - tagw.writeUI16(tag.leftMargin); - tagw.writeUI16(tag.rightMargin); - tagw.writeUI16(tag.ident); - tagw.writeSI16(tag.leading); // see errata, leading is signed - } - - tagw.writeString(tag.varName); - if (tag.hasText) - { - tagw.writeString(tag.initialText); - } - encodeTag(tag); - } - - public override void defineFont(DefineFont1 tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - - int count = tag.glyphShapeTable.Length; - - int offsetPos = tagw.Pos; - - // write offset placeholders - for (int i = 0; i < count; i++) - { - tagw.writeUI16(0); - } - - // now write glyphs and update the encoded offset table - for (int i = 0; i < count; i++) - { - tagw.writeUI16at(offsetPos + 2 * i, tagw.Pos - offsetPos); - encodeShape(tag.glyphShapeTable[i], tagw, flash.swf.TagValues_Fields.stagDefineShape3, 1, 0); - } - - encodeTag(tag); - } - - public virtual void encodeShape(Shape s, SwfEncoder w, int shape, int nFillStyles, int nLineStyles) - { - int[] numFillBits = new int[]{SwfEncoder.minBits(nFillStyles, 0)}; - int[] numLineBits = new int[]{SwfEncoder.minBits(nLineStyles, 0)}; - - w.writeUBits(numFillBits[0], 4); - w.writeUBits(numLineBits[0], 4); - - System.Collections.IEnumerator it = s.shapeRecords.GetEnumerator(); - //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" - while (it.MoveNext()) - { - //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" - ShapeRecord record = (ShapeRecord) it.Current; - if (record is StyleChangeRecord) - { - // style change - w.writeBit(false); - StyleChangeRecord change = (StyleChangeRecord) record; - encodeStyleChangeRecord(w, change, numFillBits, numLineBits, shape); - } - else - { - // edge - w.writeBit(true); - EdgeRecord e = (EdgeRecord) record; - bool straight = e is StraightEdgeRecord; - w.writeBit(straight); - int nbits = straight?calcBits((StraightEdgeRecord) e):calcBits((CurvedEdgeRecord) e); - if (nbits < 2) - nbits = 2; - w.writeUBits(nbits - 2, 4); - if (straight) - { - // line - StraightEdgeRecord line = (StraightEdgeRecord) e; - encodeStraightEdgeRecord(line, w, nbits); - } - else - { - // curve - CurvedEdgeRecord curve = (CurvedEdgeRecord) e; - w.writeSBits(curve.controlDeltaX, nbits); - w.writeSBits(curve.controlDeltaY, nbits); - w.writeSBits(curve.anchorDeltaX, nbits); - w.writeSBits(curve.anchorDeltaY, nbits); - } - } - } - - // endshaperecord - w.writeUBits(0, 6); - - w.flushBits(); - } - - private int calcBits(StraightEdgeRecord edge) - { - return SwfEncoder.minBits(SwfEncoder.maxNum(edge.deltaX, edge.deltaY, 0, 0), 1); - } - - private int calcBits(CurvedEdgeRecord edge) - { - return SwfEncoder.minBits(SwfEncoder.maxNum(edge.controlDeltaX, edge.controlDeltaY, edge.anchorDeltaX, edge.anchorDeltaY), 1); - } - - private void encodeStraightEdgeRecord(StraightEdgeRecord line, SwfEncoder w, int nbits) - { - if (line.deltaX == 0) - { - w.writeUBits(1, 2); // vertical line - w.writeSBits(line.deltaY, nbits); - } - else if (line.deltaY == 0) - { - w.writeUBits(0, 2); // horizontal line - w.writeSBits(line.deltaX, nbits); - } - else - { - w.writeBit(true); // general line - w.writeSBits(line.deltaX, nbits); - w.writeSBits(line.deltaY, nbits); - } - } - - private void encodeStyleChangeRecord(SwfEncoder w, StyleChangeRecord s, int[] numFillBits, int[] numLineBits, int shape) - { - w.writeBit(s.stateNewStyles); - w.writeBit(s.stateLineStyle); - w.writeBit(s.stateFillStyle1); - w.writeBit(s.stateFillStyle0); - w.writeBit(s.stateMoveTo); - - if (s.stateMoveTo) - { - int moveBits = s.nMoveBits(); - w.writeUBits(moveBits, 5); - w.writeSBits(s.moveDeltaX, moveBits); - w.writeSBits(s.moveDeltaY, moveBits); - } - - if (s.stateFillStyle0) - { - w.writeUBits(s.fillstyle0, numFillBits[0]); - } - - if (s.stateFillStyle1) - { - w.writeUBits(s.fillstyle1, numFillBits[0]); - } - - if (s.stateLineStyle) - { - w.writeUBits(s.linestyle, numLineBits[0]); - } - - if (s.stateNewStyles) - { - w.flushBits(); - - encodeFillstyles(s.fillstyles, w, shape); - encodeLinestyles(s.linestyles, w, shape); - - numFillBits[0] = SwfEncoder.minBits(s.fillstyles.Count, 0); - numLineBits[0] = SwfEncoder.minBits(s.linestyles.Count, 0); - w.writeUBits(numFillBits[0], 4); - w.writeUBits(numLineBits[0], 4); - } - } - - private void encodeLinestyles(System.Collections.ArrayList linestyles, SwfEncoder w, int shape) - { - int count = linestyles.Count; - if (count > 0xFF) - { - w.writeUI8(0xFF); - w.writeUI16(count); - } - else - { - w.writeUI8(count); - } - - for (int i = 0; i < count; i++) - { - encodeLineStyle((LineStyle) linestyles[i], w, shape); - } - } - - private void encodeLineStyle(LineStyle lineStyle, SwfEncoder w, int shape) - { - w.writeUI16(lineStyle.width); - - if (shape == flash.swf.TagValues_Fields.stagDefineShape6) - { - w.writeUI16(lineStyle.flags); - if (lineStyle.hasMiterJoint()) - w.writeUI16(lineStyle.miterLimit); - } - - if (shape == flash.swf.TagValues_Fields.stagDefineShape6 && lineStyle.hasFillStyle()) - { - encodeFillStyle(lineStyle.fillStyle, w, shape); - } - else if ((shape == flash.swf.TagValues_Fields.stagDefineShape3) || (shape == flash.swf.TagValues_Fields.stagDefineShape6)) - { - encodeRGBA(lineStyle.color, w); - } - else - { - encodeRGB(lineStyle.color, w); - } - } - - private void encodeFillstyles(System.Collections.ArrayList fillstyles, SwfEncoder w, int shape) - { - int count = fillstyles.Count; - if (count >= 0xFF) - { - w.writeUI8(0xFF); - w.writeUI16(count); - } - else - { - w.writeUI8(count); - } - - System.Collections.IEnumerator it = fillstyles.GetEnumerator(); - //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" - while (it.MoveNext()) - { - //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" - FillStyle style = (FillStyle) it.Current; - encodeFillStyle(style, w, shape); - } - } - - private void encodeFillStyle(FillStyle style, SwfEncoder w, int shape) - { - w.writeUI8(style.type); - switch (style.type) - { - - case FillStyle.FILL_SOLID: // 0x00 - if ((shape == flash.swf.TagValues_Fields.stagDefineShape3) || (shape == flash.swf.TagValues_Fields.stagDefineShape6)) - encodeRGBA(style.color, w); - else - encodeRGB(style.color, w); - break; - - case FillStyle.FILL_GRADIENT: - // 0x10 linear gradient fill - case FillStyle.FILL_RADIAL_GRADIENT: - // 0x12 radial gradient fill - case FillStyle.FILL_FOCAL_RADIAL_GRADIENT: // 0x13 focal radial gradient fill - encodeMatrix(style.matrix, w); - encodeGradient(style.gradient, w, shape); - break; - - case FillStyle.FILL_BITS: - // 0x40 tiled bitmap fill - case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP): - // 0x41 clipped bitmap fill - case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_NOSMOOTH): - // 0x42 tiled non-smoothed fill - case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP | FillStyle.FILL_BITS_NOSMOOTH): // 0x43 clipped non-smoothed fill - w.writeUI16(dict.getId(style.bitmap)); - encodeMatrix(style.matrix, w); - break; - } - } - - private void encodeGradient(Gradient gradient, SwfEncoder w, int shape) - { - w.writeUBits(gradient.spreadMode, 2); - w.writeUBits(gradient.interpolationMode, 2); - w.writeUBits(gradient.records.Length, 4); - for (int i = 0; i < gradient.records.Length; i++) - { - encodeGradRecord(gradient.records[i], w, shape); - } - if (gradient is FocalGradient) - { - w.writeFixed8(((FocalGradient) gradient).focalPoint); - } - } - - private void encodeGradRecord(GradRecord record, SwfEncoder w, int shape) - { - w.writeUI8(record.ratio); - if ((shape == flash.swf.TagValues_Fields.stagDefineShape3) || (shape == flash.swf.TagValues_Fields.stagDefineShape6)) - encodeRGBA(record.color, w); - else - encodeRGB(record.color, w); - } - - public override void defineFont2(DefineFont2 tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - int startPos = tagw.Pos; - bool again; - - if (tag.code == flash.swf.TagValues_Fields.stagDefineFont3) - { - tag.wideCodes = true; - } - - if (!tag.wideCodes) - { - for (int i = 0; i < tag.codeTable.Length; i++) - { - if (tag.codeTable[i] > 255) - { - tag.wideCodes = true; - break; - } - } - } - - //UPGRADE_NOTE: Label 'loop' was moved. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1014'" - do - { - again = false; - tagw.writeBit(tag.hasLayout); - tagw.writeBit(tag.shiftJIS); - tagw.writeBit(tag.smallText); - tagw.writeBit(tag.ansi); - tagw.writeBit(tag.wideOffsets); - tagw.writeBit(tag.wideCodes); - tagw.writeBit(tag.italic); - tagw.writeBit(tag.bold); - tagw.flushBits(); - - tagw.writeUI8(tag.langCode); - - tagw.writeLengthString(tag.fontName); - int count = tag.glyphShapeTable.Length; - - tagw.writeUI16(count); - int offsetPos = tagw.Pos; - - // save space for the offset table - if (tag.wideOffsets) - { - for (int i = 0; i < count; i++) - { - tagw.write32(0); - } - } - else - { - for (int i = 0; i < count; i++) - { - tagw.writeUI16(0); - } - } - - //PJF: write placeholder for codeTableOffset, this will be changed after shapes encoded - if (count > 0) - { - if (tag.wideOffsets) - { - tagw.write32(0); - } - else - { - tagw.writeUI16(0); - } - } - - for (int i = 0; i < count; i++) - { - // save offset to this glyph - int offset = tagw.Pos - offsetPos; - if (!tag.wideOffsets && offset > 65535) - { - again = true; - tag.wideOffsets = true; - tagw.Pos = startPos; - //UPGRADE_NOTE: Labeled continue statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1015'" - goto loop; - } - if (tag.wideOffsets) - tagw.write32at(offsetPos + 4 * i, offset); - else - tagw.writeUI16at(offsetPos + 2 * i, offset); - - encodeShape(tag.glyphShapeTable[i], tagw, flash.swf.TagValues_Fields.stagDefineShape3, 1, 0); - } - - // update codeTableOffset - int offset2 = tagw.Pos - offsetPos; - if (!tag.wideOffsets && offset2 > 65535) - { - again = true; - tag.wideOffsets = true; - tagw.Pos = startPos; - //UPGRADE_NOTE: Labeled continue statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1015'" - goto loop; - } - if (tag.wideOffsets) - { - tagw.write32at(offsetPos + 4 * count, offset2); - } - else - { - tagw.writeUI16at(offsetPos + 2 * count, offset2); - } - - // now write the codetable - - if (tag.wideCodes) - { - for (int i = 0; i < tag.codeTable.Length; i++) - { - tagw.writeUI16(tag.codeTable[i]); - } - } - else - { - for (int i = 0; i < tag.codeTable.Length; i++) - { - tagw.writeUI8(tag.codeTable[i]); - } - } - - if (tag.hasLayout) - { - tagw.writeSI16(tag.ascent); - tagw.writeSI16(tag.descent); - tagw.writeSI16(tag.leading); - - for (int i = 0; i < tag.advanceTable.Length; i++) - { - tagw.writeSI16(tag.advanceTable[i]); - } - - for (int i = 0; i < tag.boundsTable.Length; i++) - { - encodeRect(tag.boundsTable[i], tagw); - } - - tagw.writeUI16(tag.kerningTable.Length); - - for (int i = 0; i < tag.kerningTable.Length; i++) - { - if (!tag.wideCodes && ((tag.kerningTable[i].code1 > 255) || (tag.kerningTable[i].code2 > 255))) - { - again = true; - tag.wideCodes = true; - tagw.Pos = startPos; - //UPGRADE_NOTE: Labeled continue statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1015'" - goto loop; - } - - encodeKerningRecord(tag.kerningTable[i], tagw, tag.wideCodes); - } - } - //UPGRADE_NOTE: Label 'loop' was moved. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1014'" -loop: ; - } - while (again); - - encodeTag(tag); - } - - public override void defineFont3(DefineFont3 tag) - { - defineFont2(tag); - } - - public override void defineFont4(DefineFont4 tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - - tagw.writeUBits(0, 5); // reserved - tagw.writeBit(tag.hasFontData); - //tagw.writeBit(tag.smallText); - tagw.writeBit(tag.italic); - tagw.writeBit(tag.bold); - tagw.flushBits(); - - //tagw.writeUI8(tag.langCode); - tagw.writeString(tag.fontName); - if (tag.hasFontData) - { - tagw.write(tag.data); - } - - encodeTag(tag); - } - - public override void defineFontAlignZones(DefineFontAlignZones tag) - { - int fontID = dict.getId(tag.font); - tagw.writeUI16(fontID); - tagw.writeUBits(tag.csmTableHint, 2); - tagw.writeUBits(0, 6); // reserved - for (int i = 0; i < tag.zoneTable.Length; i++) - { - ZoneRecord record = tag.zoneTable[i]; - tagw.writeUI8(record.numZoneData); - for (int j = 0; j < record.numZoneData; j++) - { - tagw.write32((int) record.zoneData[j]); - } - tagw.writeUI8(record.zoneMask); - } - encodeTag(tag); - } - - public override void csmTextSettings(CSMTextSettings tag) - { - int textID = 0; - if (tag.textReference != null) - { - textID = dict.getId(tag.textReference); - } - tagw.writeUI16(textID); - tagw.writeUBits(tag.styleFlagsUseSaffron, 2); - tagw.writeUBits(tag.gridFitType, 3); - tagw.writeUBits(0, 3); // reserved - // FIXME: thickness/sharpness should be written out as 32 bit IEEE Single Precision format in little Endian - tagw.writeUBits((int) tag.thickness, 32); - tagw.writeUBits((int) tag.sharpness, 32); - tagw.writeUBits(0, 8); //reserved - - encodeTag(tag); - } - - public override void defineFontName(DefineFontName tag) - { - int fontID = dict.getId(tag.font); - tagw.writeUI16(fontID); - if (tag.fontName != null) - { - tagw.writeString(tag.fontName); - } - else - { - tagw.writeString(""); - } - if (tag.copyright != null) - { - tagw.writeString(tag.copyright); - } - else - { - tagw.writeString(""); - } - - encodeTag(tag); - } - - private void encodeKerningRecord(KerningRecord kerningRecord, SwfEncoder w, bool wideCodes) - { - if (wideCodes) - { - w.writeUI16(kerningRecord.code1); - w.writeUI16(kerningRecord.code2); - } - else - { - w.writeUI8(kerningRecord.code1); - w.writeUI8(kerningRecord.code2); - } - w.writeUI16(kerningRecord.adjustment); - } - - public override void defineFontInfo(DefineFontInfo tag) - { - int idref = dict.getId(tag.font); - tagw.writeUI16(idref); - - tagw.writeLengthString(tag.name); - - tagw.writeUBits(0, 3); // reserved - tagw.writeBit(tag.shiftJIS); - tagw.writeBit(tag.ansi); - tagw.writeBit(tag.italic); - tagw.writeBit(tag.bold); - - if (tag.code == flash.swf.TagValues_Fields.stagDefineFontInfo2) - { - tagw.writeBit(tag.wideCodes = true); - tagw.writeUI8(tag.langCode); - } - else - { - if (!tag.wideCodes) - { - for (int i = 0; i < tag.codeTable.Length; i++) - { - if (tag.codeTable[i] > 255) - { - tag.wideCodes = true; - break; - } - } - } - tagw.writeBit(tag.wideCodes); - } - - if (tag.wideCodes) - { - for (int i = 0; i < tag.codeTable.Length; i++) - tagw.writeUI16(tag.codeTable[i]); - } - else - { - for (int i = 0; i < tag.codeTable.Length; i++) - tagw.writeUI8(tag.codeTable[i]); - } - encodeTag(tag); - } - - public override void defineFontInfo2(DefineFontInfo tag) - { - defineFontInfo(tag); - } - - public override void defineMorphShape(DefineMorphShape tag) - { - defineMorphShape2(tag); - } - - public override void defineMorphShape2(DefineMorphShape tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - encodeRect(tag.startBounds, tagw); - encodeRect(tag.endBounds, tagw); - if (tag.code == flash.swf.TagValues_Fields.stagDefineMorphShape2) - { - encodeRect(tag.startEdgeBounds, tagw); - encodeRect(tag.endEdgeBounds, tagw); - tagw.writeUBits(tag.reserved, 6); - tagw.writeUBits(tag.usesNonScalingStrokes?1:0, 1); - tagw.writeUBits(tag.usesScalingStrokes?1:0, 1); - } - tagw.write32(0); - int pos = tagw.Pos; - encodeMorphFillstyles(tag.fillStyles, tagw, tag.code); - encodeMorphLinestyles(tag.lineStyles, tagw, tag.code); - encodeShape(tag.startEdges, tagw, flash.swf.TagValues_Fields.stagDefineShape3, tag.fillStyles.Length, tag.lineStyles.Length); - tagw.write32at(pos - 4, tagw.Pos - pos); - // end shape contains only edges, no style information - encodeShape(tag.endEdges, tagw, flash.swf.TagValues_Fields.stagDefineShape3, 0, 0); - encodeTag(tag); - } - - private void encodeMorphFillstyles(MorphFillStyle[] fillStyles, SwfEncoder w, int code) - { - int count = fillStyles.Length; - if (count >= 0xFF) - { - w.writeUI8(0xFF); - w.writeUI16(count); - } - else - { - w.writeUI8(count); - } - - for (int i = 0; i < count; i++) - { - encodeMorphFillstyle(fillStyles[i], w, code); - } - } - - private void encodeMorphFillstyle(MorphFillStyle style, SwfEncoder w, int code) - { - w.writeUI8(style.type); - switch (style.type) - { - - case FillStyle.FILL_SOLID: // 0x00 - encodeRGBA(style.startColor, w); - encodeRGBA(style.endColor, w); - break; - - case FillStyle.FILL_GRADIENT: - // 0x10 linear gradient fill - case FillStyle.FILL_RADIAL_GRADIENT: - // 0x12 radial gradient fill - case FillStyle.FILL_FOCAL_RADIAL_GRADIENT: // 0x13 focal radial gradient fill - encodeMatrix(style.startGradientMatrix, w); - encodeMatrix(style.endGradientMatrix, w); - encodeMorphGradient(style.gradRecords, w); - if (style.type == FillStyle.FILL_FOCAL_RADIAL_GRADIENT && code == flash.swf.TagValues_Fields.stagDefineMorphShape2) - { - w.writeSI16(style.ratio1); - w.writeSI16(style.ratio2); - } - break; - - case FillStyle.FILL_BITS: - // 0x40 tiled bitmap fill - case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP): - // 0x41 clipped bitmap fill - case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_NOSMOOTH): - // 0x42 tiled non-smoothed fill - case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP | FillStyle.FILL_BITS_NOSMOOTH): // 0x43 clipped non-smoothed fill - w.writeUI16(dict.getId(style.bitmap)); - encodeMatrix(style.startBitmapMatrix, w); - encodeMatrix(style.endBitmapMatrix, w); - break; - - default: - assert(false); - //throw new IOException("unrecognized fill style type: " + style.type); - break; - - } - } - - private void encodeMorphGradient(MorphGradRecord[] gradRecords, SwfEncoder w) - { - w.writeUI8(gradRecords.Length); - for (int i = 0; i < gradRecords.Length; i++) - { - MorphGradRecord record = gradRecords[i]; - w.writeUI8(record.startRatio); - encodeRGBA(record.startColor, w); - w.writeUI8(record.endRatio); - encodeRGBA(record.endColor, w); - } - } - - private void encodeMorphLinestyles(MorphLineStyle[] lineStyles, SwfEncoder w, int code) - { - if (lineStyles.Length >= 0xFF) - { - w.writeUI8(0xFF); - w.writeUI16(lineStyles.Length); - } - else - { - w.writeUI8(lineStyles.Length); - } - - for (int i = 0; i < lineStyles.Length; i++) - { - MorphLineStyle style = lineStyles[i]; - w.writeUI16(style.startWidth); - w.writeUI16(style.endWidth); - if (code == flash.swf.TagValues_Fields.stagDefineMorphShape2) - { - w.writeUBits(style.startCapsStyle, 2); - w.writeUBits(style.jointStyle, 2); - w.writeBit(style.hasFill); - w.writeBit(style.noHScale); - w.writeBit(style.noVScale); - w.writeBit(style.pixelHinting); - w.writeUBits(0, 5); // reserved - w.writeBit(style.noClose); - w.writeUBits(style.endCapsStyle, 2); - if (style.jointStyle == 2) - { - w.writeUI16(style.miterLimit); - } - } - if (!style.hasFill) - { - encodeRGBA(style.startColor, w); - encodeRGBA(style.endColor, w); - } - if (style.hasFill) - { - encodeMorphFillstyle(style.fillType, w, code); - } - } - } - - public override void defineShape(DefineShape tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - encodeRect(tag.bounds, tagw); - if (tag.code == flash.swf.TagValues_Fields.stagDefineShape6) - { - encodeRect(tag.edgeBounds, tagw); - tagw.writeUBits(0, 6); - tagw.writeBit(tag.usesNonScalingStrokes); - tagw.writeBit(tag.usesScalingStrokes); - } - encodeShapeWithStyle(tag.shapeWithStyle, tagw, tag.code); - encodeTag(tag); - } - - private void encodeShapeWithStyle(ShapeWithStyle shapeWithStyle, SwfEncoder w, int shape) - { - encodeFillstyles(shapeWithStyle.fillstyles, w, shape); - encodeLinestyles(shapeWithStyle.linestyles, w, shape); - - encodeShape(shapeWithStyle, w, shape, shapeWithStyle.fillstyles.Count, shapeWithStyle.linestyles.Count); - } - - public override void defineShape2(DefineShape tag) - { - defineShape(tag); - } - - public override void defineShape3(DefineShape tag) - { - defineShape(tag); - } - - public override void defineShape6(DefineShape tag) - { - defineShape(tag); - } - - public override void defineSound(DefineSound tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - tagw.writeUBits(tag.format, 4); - tagw.writeUBits(tag.rate, 2); - tagw.writeUBits(tag.size, 1); - tagw.writeUBits(tag.type, 1); - tagw.write32((int) tag.sampleCount); - tagw.write(tag.data); - encodeTag(tag); - } - - public override void defineSprite(DefineSprite tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - tagw.writeUI16(tag.framecount); - - if (Debug) - { - debug.adjust = writer.Pos + 6; - } - - // save frame count - int oldFrames = frames; - frames = 0; - - // save the movie writer, and push a new writer - SwfEncoder oldWriter = writer; - writer = tagw; - tagw = createEncoder(SwfVersion); - - // write sprite tags - System.Collections.IList tags = tag.tagList.tags; - int size = tags.Count; - for (int i = 0; i < size; i++) - { - Tag t = (Tag) tags[i]; - if (!(t is DefineTag)) - t.visit(this); - } - - // terminate with end marker - writer.writeUI16(0); - - // update frame count - writer.writeUI16at(2, frames); - - // restore writers - tagw = writer; - writer = oldWriter; - frames = oldFrames; - - if (Debug) - { - debug.adjust = 0; - } - - encodeTag(tag); - } - - public override void defineText(DefineText tag) - { - encodeDefineText(tag, tagw, tag.code); - encodeTag(tag); - } - - private void encodeDefineText(DefineText tag, SwfEncoder w, int type) - { - int id = dict.add(tag); - w.writeUI16(id); - encodeRect(tag.bounds, w); - encodeMatrix(tag.matrix, w); - int length = tag.records.Count; - - // compute necessary bit width - int glyphBits = 0; - int advanceBits = 0; - for (int i = 0; i < length; i++) - { - TextRecord tr = (TextRecord) tag.records[i]; - - for (int j = 0; j < tr.entries.Length; j++) - { - GlyphEntry entry = tr.entries[j]; - - while (entry.Index > (1 << glyphBits)) - glyphBits++; - while (System.Math.Abs(entry.advance) > (1 << advanceBits)) - advanceBits++; - } - } - - // increment to get from bit index to bit count. - ++glyphBits; - ++advanceBits; - - w.writeUI8(glyphBits); - w.writeUI8(++advanceBits); // add one extra bit because advances are signed - - for (int i = 0; i < length; i++) - { - TextRecord record = (TextRecord) tag.records[i]; - encodeTextRecord(record, w, type, glyphBits, advanceBits); - } - - w.writeUI8(0); - } - - private void encodeFilterList(System.Collections.IList filters, SwfEncoder w) - { - int count = filters.Count; - w.writeUI8(count); - //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" - for (System.Collections.IEnumerator it = filters.GetEnumerator(); it.MoveNext(); ) - { - //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" - Filter f = (Filter) it.Current; - w.writeUI8(f.getID()); - // I've never quite understood why the serialization code isn't in the tags themselves.. - switch (f.getID()) - { - - case DropShadowFilter.ID: encodeDropShadowFilter(w, (DropShadowFilter) f); break; - - case BlurFilter.ID: encodeBlurFilter(w, (BlurFilter) f); break; - - case ConvolutionFilter.ID: encodeConvolutionFilter(w, (ConvolutionFilter) f); break; - - case GlowFilter.ID: encodeGlowFilter(w, (GlowFilter) f); break; - - case BevelFilter.ID: encodeBevelFilter(w, (BevelFilter) f); break; - - case ColorMatrixFilter.ID: encodeColorMatrixFilter(w, (ColorMatrixFilter) f); break; - - case GradientGlowFilter.ID: encodeGradientGlowFilter(w, (GradientGlowFilter) f); break; - - case GradientBevelFilter.ID: encodeGradientBevelFilter(w, (GradientBevelFilter) f); break; - } - } - } - - private void encodeDropShadowFilter(SwfEncoder w, DropShadowFilter f) - { - encodeRGBA(f.color, w); - w.write32(f.blurX); - w.write32(f.blurY); - w.write32(f.angle); - w.write32(f.distance); - w.writeUI16(f.strength); - w.writeUI8(f.flags); - } - - private void encodeBlurFilter(SwfEncoder w, BlurFilter f) - { - w.write32(f.blurX); - w.write32(f.blurY); - w.writeUI8(f.passes); - } - private void encodeColorMatrixFilter(SwfEncoder w, ColorMatrixFilter f) - { - for (int i = 0; i < 20; ++i) - { - w.writeFloat(f.values[i]); - } - } - private void encodeConvolutionFilter(SwfEncoder w, ConvolutionFilter f) - { - w.writeUI8(f.matrixX); - w.writeUI8(f.matrixY); - w.writeFloat(f.divisor); - w.writeFloat(f.bias); - for (int i = 0; i < f.matrix.Length; ++i) - w.writeFloat(f.matrix[i]); - w.writeUI8(f.flags); - } - private void encodeGlowFilter(SwfEncoder w, GlowFilter f) - { - encodeRGBA(f.color, w); - w.write32(f.blurX); - w.write32(f.blurY); - w.writeUI16(f.strength); - w.writeUI8(f.flags); - } - private void encodeBevelFilter(SwfEncoder w, BevelFilter f) - { - encodeRGBA(f.shadowColor, w); - encodeRGBA(f.highlightColor, w); - w.write32(f.blurX); - w.write32(f.blurY); - w.write32(f.angle); - w.write32(f.distance); - w.writeUI16(f.strength); - w.writeUI8(f.flags); - } - - private void encodeGradientGlowFilter(SwfEncoder w, GradientGlowFilter f) - { - w.writeUI8(f.numcolors); - for (int i = 0; i < f.numcolors; ++i) - encodeRGBA(f.gradientColors[i], w); - for (int i = 0; i < f.numcolors; ++i) - w.writeUI8(f.gradientRatio[i]); - //w.write32( f.color ); - w.write32(f.blurX); - w.write32(f.blurY); - w.write32(f.angle); - w.write32(f.distance); - w.writeUI16(f.strength); - w.writeUI8(f.flags); - } - private void encodeGradientBevelFilter(SwfEncoder w, GradientBevelFilter f) - { - w.writeUI8(f.numcolors); - for (int i = 0; i < f.numcolors; ++i) - encodeRGBA(f.gradientColors[i], w); - for (int i = 0; i < f.numcolors; ++i) - w.writeUI8(f.gradientRatio[i]); - - // w.write32( f.shadowColor ); - // w.write32( f.highlightColor ); - w.write32(f.blurX); - w.write32(f.blurY); - w.write32(f.angle); - w.write32(f.distance); - w.writeUI16(f.strength); - w.writeUI8(f.flags); - } - - private void encodeTextRecord(TextRecord record, SwfEncoder w, int type, int glyphBits, int advanceBits) - { - w.writeUI8(record.flags); - - if (record.hasFont()) - { - w.writeUI16(dict.getId(record.font)); - } - - if (record.hasColor()) - { - if (type == flash.swf.TagValues_Fields.stagDefineText2) - encodeRGBA(record.color, w); - else - encodeRGB(record.color, w); - } - - if (record.hasX()) - { - w.writeSI16(record.xOffset); - } - - if (record.hasY()) - { - w.writeSI16(record.yOffset); - } - - if (record.hasHeight()) - { - w.writeUI16(record.height); - } - - w.writeUI8(record.entries.Length); - - for (int i = 0; i < record.entries.Length; i++) - { - w.writeUBits(record.entries[i].Index, glyphBits); - w.writeSBits(record.entries[i].advance, advanceBits); - } - w.flushBits(); - } - - public override void defineText2(DefineText tag) - { - defineText(tag); - } - - public override void defineVideoStream(DefineVideoStream tag) - { - int id = dict.add(tag); - tagw.writeUI16(id); - tagw.writeUI16(tag.numFrames); - tagw.writeUI16(tag.width); - tagw.writeUI16(tag.height); - - tagw.writeUBits(0, 4); // reserved - tagw.writeUBits(tag.deblocking, 3); - tagw.writeBit(tag.smoothing); - - tagw.writeUI8(tag.codecID); - encodeTag(tag); - } - - public override void doAction(DoAction tag) - { - int adjust = 0; - if (Debug) - { - adjust = writer.Pos + 6; - debug.adjust += adjust; - } - - new ActionEncoder(tagw, debug).encode(tag.actionList); - tagw.writeUI8(0); - encodeTag(tag); - - if (Debug) - { - debug.adjust -= adjust; - } - } - - public override void doInitAction(DoInitAction tag) - { - int adjust = 0; - if (Debug) - { - adjust = writer.Pos + 6; - debug.adjust += adjust; - } - - int idref = dict.getId(tag.sprite); - tagw.writeUI16(idref); - new ActionEncoder(tagw, debug).encode(tag.actionList); - tagw.writeUI8(0); - encodeTag(tag); - - if (Debug) - { - debug.adjust -= adjust; - } - } - - public override void enableDebugger(EnableDebugger tag) - { - tagw.writeString(tag.password); - encodeTag(tag); - } - - public override void enableDebugger2(EnableDebugger tag) - { - // This corresponds to the constant used in the player, - // core/splay.cpp, in ScriptThread::EnableDebugger(). - tagw.writeUI16(0x1975); - tagw.writeString(tag.password); - encodeTag(tag); - } - - public override void exportAssets(ExportAssets tag) - { - tagw.writeUI16(tag.exports.Count); - System.Collections.IEnumerator it = tag.exports.GetEnumerator(); - //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" - while (it.MoveNext()) - { - //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" - DefineTag ref_Renamed = (DefineTag) it.Current; - int idref = dict.getId(ref_Renamed); - tagw.writeUI16(idref); - assert(ref_Renamed.name != null); // exported symbols must have names - tagw.writeString(ref_Renamed.name); - dict.addName(ref_Renamed, ref_Renamed.name); - } - encodeTag(tag); - } - - public override void symbolClass(SymbolClass tag) - { - tagw.writeUI16(tag.class2tag.Count + (tag.topLevelClass != null?1:0)); - //UPGRADE_TODO: Method 'java.util.Map.entrySet' was converted to 'SupportClass.HashSetSupport' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilMapentrySet'" - System.Collections.IEnumerator it = new SupportClass.HashSetSupport(tag.class2tag).GetEnumerator(); - //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" - while (it.MoveNext()) - { - //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" - System.Collections.DictionaryEntry e = (System.Collections.DictionaryEntry) it.Current; - System.String name = (System.String) e.Key; - DefineTag ref_Renamed = (DefineTag) e.Value; - - int idref = dict.getId(ref_Renamed); - tagw.writeUI16(idref); - tagw.writeString(name); - } - if (tag.topLevelClass != null) - { - tagw.writeUI16(0); - tagw.writeString(tag.topLevelClass); - } - encodeTag(tag); - } - - public override void frameLabel(FrameLabel tag) - { - tagw.writeString(tag.label); - if (tag.anchor && SwfVersion >= 6) - { - tagw.writeUI8(1); - } - encodeTag(tag); - } - - public override void importAssets(ImportAssets tag) - { - tagw.writeString(tag.url); - if (tag.code == flash.swf.TagValues_Fields.stagImportAssets2) - { - tagw.writeUI8(tag.downloadNow?1:0); - tagw.writeUI8(tag.SHA1 != null?1:0); - if (tag.SHA1 != null) - { - tagw.write(tag.SHA1); - } - } - tagw.writeUI16(tag.importRecords.Count); - System.Collections.IEnumerator it = tag.importRecords.GetEnumerator(); - //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" - while (it.MoveNext()) - { - //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" - ImportRecord record = (ImportRecord) it.Current; - int id = dict.add(record); - tagw.writeUI16(id); - tagw.writeString(record.name); - } - encodeTag(tag); - } - - public override void importAssets2(ImportAssets tag) - { - importAssets(tag); - } - - public override void jpegTables(GenericTag tag) - { - encodeTagHeader(tag.code, tag.data.Length, false); - writer.write(tag.data); - } - - public override void placeObject(PlaceObject tag) - { - int idref = dict.getId(tag.ref_Renamed); - tagw.writeUI16(idref); - tagw.writeUI16(tag.depth); - encodeMatrix(tag.matrix, tagw); - if (tag.colorTransform != null) - { - encodeCxform(tag.colorTransform, tagw); - } - encodeTag(tag); - } - - public override void placeObject2(PlaceObject tag) - { - placeObject23(tag); - } - - public override void placeObject3(PlaceObject tag) - { - placeObject23(tag); - } - - public virtual void placeObject23(PlaceObject tag) - { - tagw.writeUI8(tag.flags); - if (tag.code == flash.swf.TagValues_Fields.stagPlaceObject3) - { - tagw.writeUI8(tag.flags2); - } - tagw.writeUI16(tag.depth); - if (tag.hasClassName()) - { - tagw.writeString(tag.className); - } - if (tag.hasCharID()) - { - int idref = dict.getId(tag.ref_Renamed); - tagw.writeUI16(idref); - } - if (tag.hasMatrix()) - { - encodeMatrix(tag.matrix, tagw); - } - if (tag.hasCxform()) - { - // ed 5/22/03 the SWF 6 file format spec says this should be a CXFORM, but - // the spec is wrong. the player expects a CXFORMA. - encodeCxforma(((CXFormWithAlpha) tag.colorTransform), tagw); - } - if (tag.hasRatio()) - { - tagw.writeUI16(tag.ratio); - } - if (tag.hasName()) - { - tagw.writeString(tag.name); - } - if (tag.hasClipDepth()) - { - tagw.writeUI16(tag.clipDepth); - } - if (tag.code == flash.swf.TagValues_Fields.stagPlaceObject3) - { - if (tag.hasFilterList()) - { - encodeFilterList(tag.filters, tagw); - } - if (tag.hasBlendMode()) - { - tagw.writeUI8(tag.blendMode); - } - } - if (tag.hasClipAction()) - { - int adjust = 0; - if (Debug) - { - adjust = writer.Pos + 6; - debug.adjust += adjust; - } - new ActionEncoder(tagw, debug).encodeClipActions(tag.clipActions); - if (Debug) - { - debug.adjust -= adjust; - } - } - encodeTag(tag); - } - - public override void protect(GenericTag tag) - { - if (tag.data != null) - { - encodeTagHeader(tag.code, tag.data.Length, false); - writer.write(tag.data); - } - else - { - encodeTagHeader(tag.code, 0, false); - } - } - - public override void removeObject(RemoveObject tag) - { - encodeTagHeader(tag.code, 4, false); - int idref = dict.getId(tag.ref_Renamed); - writer.writeUI16(idref); - writer.writeUI16(tag.depth); - } - - public override void removeObject2(RemoveObject tag) - { - encodeTagHeader(tag.code, 2, false); - writer.writeUI16(tag.depth); - } - - public override void showFrame(ShowFrame tag) - { - encodeTagHeader(tag.code, 0, false); - frames++; - } - - public override void soundStreamBlock(GenericTag tag) - { - encodeTagHeader(tag.code, tag.data.Length, false); - writer.write(tag.data); - } - - public override void soundStreamHead(SoundStreamHead tag) - { - int length = 4; - - // we need to add two bytes for an extra SI16 (latencySeek) - if (tag.compression == SoundStreamHead.sndCompressMP3) - { - length += 2; - } - - encodeTagHeader(tag.code, length, false); - - // 1 byte - writer.writeUBits(0, 4); // reserved - writer.writeUBits(tag.playbackRate, 2); - writer.writeUBits(tag.playbackSize, 1); - writer.writeUBits(tag.playbackType, 1); - - // 1 byte - writer.writeUBits(tag.compression, 4); - writer.writeUBits(tag.streamRate, 2); - writer.writeUBits(tag.streamSize, 1); - writer.writeUBits(tag.streamType, 1); - - // 2 bytes - writer.writeUI16(tag.streamSampleCount); - - if (tag.compression == SoundStreamHead.sndCompressMP3) - { - // 2 bytes - writer.writeSI16(tag.latencySeek); - } - } - - public override void soundStreamHead2(SoundStreamHead tag) - { - soundStreamHead(tag); - } - - public override void startSound(StartSound tag) - { - int idref = dict.getId(tag.sound); - tagw.writeUI16(idref); - encodeSoundInfo(tag.soundInfo, tagw); - encodeTag(tag); - } - - public override void videoFrame(VideoFrame tag) - { - encodeTagHeader(tag.code, 4 + tag.videoData.Length, false); - int idref = dict.getId(tag.stream); - writer.writeUI16(idref); - writer.writeUI16(tag.frameNum); - writer.write(tag.videoData); - } - - public override void defineSceneAndFrameLabelData(DefineSceneAndFrameLabelData tag) - { - encodeTagHeader(tag.code, tag.data.Length, false); - writer.write(tag.data); - } - - public override void doABC(DoABC tag) - { - if (tag.code == flash.swf.TagValues_Fields.stagDoABC2) - { - encodeTagHeader(tag.code, 4 + tag.name.Length + 1 + tag.abc.Length, false); - writer.write32(tag.flag); - writer.writeString(tag.name); - } - else - { - encodeTagHeader(tag.code, tag.abc.Length, false); - } - - writer.write(tag.abc); - } - - public override void unknown(GenericTag tag) - { - encodeTagHeader(tag.code, tag.data.Length, false); - writer.write(tag.data); - } - - public virtual sbyte[] toByteArray() - { - //TODO this could be improved, tricky bit is that writeTo is not trivial - // and has the side effect of compressing (meaning the writer.size() - // may be larger than necessary) - System.IO.MemoryStream out_Renamed = new System.IO.MemoryStream(writer.Length); - writeTo(out_Renamed); - return SupportClass.ToSByteArray(out_Renamed.ToArray()); - } - - public override void scriptLimits(ScriptLimits tag) - { - tagw.writeUI16(tag.scriptRecursionLimit); - tagw.writeUI16(tag.scriptTimeLimit); - encodeTag(tag); - } - } +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2003-2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// +using System; +using flash.swf.tags; +using ButtonCondAction = flash.swf.types.ButtonCondAction; +using ButtonRecord = flash.swf.types.ButtonRecord; +using CXForm = flash.swf.types.CXForm; +using CXFormWithAlpha = flash.swf.types.CXFormWithAlpha; +using CurvedEdgeRecord = flash.swf.types.CurvedEdgeRecord; +using EdgeRecord = flash.swf.types.EdgeRecord; +using FillStyle = flash.swf.types.FillStyle; +using GlyphEntry = flash.swf.types.GlyphEntry; +using GradRecord = flash.swf.types.GradRecord; +using ImportRecord = flash.swf.types.ImportRecord; +using KerningRecord = flash.swf.types.KerningRecord; +using LineStyle = flash.swf.types.LineStyle; +using MD5 = flash.swf.types.MD5; +using Matrix = flash.swf.types.Matrix; +using MorphFillStyle = flash.swf.types.MorphFillStyle; +using MorphGradRecord = flash.swf.types.MorphGradRecord; +using MorphLineStyle = flash.swf.types.MorphLineStyle; +using Rect = flash.swf.types.Rect; +using Shape = flash.swf.types.Shape; +using ShapeRecord = flash.swf.types.ShapeRecord; +using ShapeWithStyle = flash.swf.types.ShapeWithStyle; +using SoundInfo = flash.swf.types.SoundInfo; +using StraightEdgeRecord = flash.swf.types.StraightEdgeRecord; +using StyleChangeRecord = flash.swf.types.StyleChangeRecord; +using TextRecord = flash.swf.types.TextRecord; +using Filter = flash.swf.types.Filter; +using DropShadowFilter = flash.swf.types.DropShadowFilter; +using BlurFilter = flash.swf.types.BlurFilter; +using ColorMatrixFilter = flash.swf.types.ColorMatrixFilter; +using GlowFilter = flash.swf.types.GlowFilter; +using ConvolutionFilter = flash.swf.types.ConvolutionFilter; +using BevelFilter = flash.swf.types.BevelFilter; +using GradientGlowFilter = flash.swf.types.GradientGlowFilter; +using GradientBevelFilter = flash.swf.types.GradientBevelFilter; +using Gradient = flash.swf.types.Gradient; +using FocalGradient = flash.swf.types.FocalGradient; +namespace flash.swf +{ + + public class TagEncoder:TagHandler, TagValues + { + virtual public int Pos + { + get + { + return writer.Pos; + } + + } + virtual protected internal int SwfVersion + { + get + { + return header_Renamed_Field.version; + } + + } + virtual protected internal int FrameRate + { + get + { + return header_Renamed_Field.rate; + } + + } + virtual public Dictionary EncoderDictionary + { + set + { + assert((this.dict == null) || (this.dict.ids.Count == 0)); + this.dict = value; + } + + } + virtual public Dictionary Dictionary + { + get + { + return dict; + } + + } + virtual public bool Debug + { + get + { + return debug != null; + } + + } + virtual public int Width + { + get + { + return width / 20; + } + + } + virtual public int Height + { + get + { + return height / 20; + } + + } + virtual public System.String MainDebugScript + { + set + { + debug.MainDebugScript = value; + } + + } + override public SetBackgroundColor BackgroundColor + { + set + { + encodeTagHeader(value.code, 3, false); + encodeRGB(value.color, writer); + } + + } + override public SetTabIndex TabIndex + { + set + { + tagw.writeUI16(value.depth); + tagw.writeUI16(value.index); + encodeTag(value); + } + + } + // changed from private to protected to support Flash Authoring - jkamerer 2007.07.30 + protected internal SwfEncoder writer; + private SwfEncoder tagw; + private int width; + private int height; + private int frames; + private int framecountPos; + private DebugEncoder debug; + private Header header_Renamed_Field; + + protected internal Dictionary dict; + private int uuidOffset; + + public TagEncoder() + { + dict = new Dictionary(); + } + + public TagEncoder(Dictionary dict) + { + this.dict = dict; + } + + public override void productInfo(ProductInfo tag) + { + tagw.write32(tag.Product); + tagw.write32(tag.Edition); + tagw.write(new sbyte[]{tag.MajorVersion, tag.MinorVersion}); + tagw.write64(tag.Build); + tagw.write64(tag.CompileDate); + encodeTag(tag); + } + + public override void fileAttributes(FileAttributes tag) + { + tagw.writeUBits(0, 3); + tagw.writeBit(tag.hasMetadata); + tagw.writeBit(tag.actionScript3); + tagw.writeBit(tag.suppressCrossDomainCaching); + tagw.writeBit(tag.swfRelativeUrls); + tagw.writeBit(tag.useNetwork); + tagw.writeUBits(0, 24); + encodeTag(tag); + } + + public override void metadata(Metadata tag) + { + tagw.writeString(tag.xml); + encodeTag(tag); + } + + protected internal virtual SwfEncoder createEncoder(int swfVersion) + { + return new SwfEncoder(swfVersion); + } + + public override void header(Header header) + { + // get some header properties we need to know + int swfVersion = header.version; + this.header_Renamed_Field = header; + this.writer = createEncoder(swfVersion); + this.tagw = createEncoder(swfVersion); + width = header.size.Width; + height = header.size.Height; + frames = 0; + + // write the header + writer.writeUI8(header.compressed?'C':'F'); + writer.writeUI8('W'); + writer.writeUI8('S'); + writer.writeUI8(header.version); + writer.write32((int) header.length); + if (header.compressed) + { + writer.markComp(); + } + encodeRect(header.size, writer); + writer.writeUI8(header.rate >> 8); + writer.writeUI8(header.rate & 255); + framecountPos = writer.Pos; + writer.writeUI16(header.framecount); + } + + public override void finish() + { + // write end marker + writer.writeUI16(0); + + // update the length + writer.write32at(4, writer.Pos); + + // update the frame count + writer.writeUI16at(framecountPos, frames); + + if (debug != null) + { + // compute a crc and use it for the debug id. that way it + // is wholly dependent on the bytes in the SWF and not some + // outside value. If any of the bytes are different, + // then the UUID will be different. + sbyte[] md5 = MD5.getDigest(writer.ByteArray, writer.Length); + writer.writeAt(uuidOffset, md5); + debug.updateUUID(md5); + } + } + + public virtual void writeTo(System.IO.Stream out_Renamed) + { + writer.WriteTo(out_Renamed); + } + + + public virtual void writeDebugTo(System.IO.Stream out_Renamed) + { + debug.writeTo(out_Renamed); + } + + public virtual void encodeRect(Rect r, SwfEncoder w) + { + int nBits = r.nbits(); + w.writeUBits(nBits, 5); + w.writeSBits(r.xMin, nBits); + w.writeSBits(r.xMax, nBits); + w.writeSBits(r.yMin, nBits); + w.writeSBits(r.yMax, nBits); + w.flushBits(); + } + + public override void debugID(DebugID tag) + { + encodeTagHeader(tag.code, tag.uuid.bytes.Length, false); + uuidOffset = writer.Pos; + writer.write(tag.uuid.bytes); + + debug = new DebugEncoder(); + debug.header(SwfVersion); + debug.uuid(tag.uuid); + } + + private void encodeTag(Tag tag) + { + try + { + tagw.compress(); + encodeTagHeader(tag.code, tagw.Pos, isLongHeader(tag)); + tagw.WriteTo(writer); + tagw.reset(); + } + catch (System.IO.IOException e) + { + assert(false); + } + } + + private bool isLongHeader(Tag t) + { + switch (t.code) + { + + // [preilly] In the player code, ScriptThread::DefineBits() assumes all DefineBits + // tags use a long header. See "ch->data = AttachData(pos-8);". If the player + // also supported a short header, it would use "pos-4". + case flash.swf.TagValues_Fields.stagDefineBits: + case flash.swf.TagValues_Fields.stagDefineBitsJPEG2: + case flash.swf.TagValues_Fields.stagDefineBitsJPEG3: + case flash.swf.TagValues_Fields.stagDefineBitsLossless: + case flash.swf.TagValues_Fields.stagDefineBitsLossless2: + return true; + + // [ed] the FlashPaper codebase also indicates that stagSoundStreamBlock must use + // a long format header. todo - verify by looking at the player code. + + case flash.swf.TagValues_Fields.stagSoundStreamBlock: + return true; + + // [edsmith] these tags have code in them. When we're writing a SWD, we use long headers + // so we can predict SWF offsets correctly when writing SWD line/offset records. + + case flash.swf.TagValues_Fields.stagDefineButton: + case flash.swf.TagValues_Fields.stagDefineButton2: + case flash.swf.TagValues_Fields.stagDefineSprite: + case flash.swf.TagValues_Fields.stagDoInitAction: + case flash.swf.TagValues_Fields.stagDoAction: + return Debug; + + + case flash.swf.TagValues_Fields.stagPlaceObject2: + return Debug && ((PlaceObject) t).hasClipAction(); + + // all other tags will use short/long headers depending on their length + + default: + return false; + + } + } + + private void encodeTagHeader(int code, int length, bool longHeader) + { + if (longHeader || length >= 63) + { + writer.writeUI16((code << 6) | 63); + writer.write32(length); + } + else + { + writer.writeUI16((code << 6) | length); + } + } + + public override void defineScalingGrid(DefineScalingGrid tag) + { + int idref = dict.getId(tag.scalingTarget); + tagw.writeUI16(idref); + encodeRect(tag.rect, tagw); + encodeTag(tag); + } + + public override void defineBinaryData(DefineBinaryData tag) + { + encodeTagHeader(tag.code, 6 + tag.data.Length, false); + int id = dict.add(tag); + writer.writeUI16(id); + writer.write32(tag.reserved); + writer.write(tag.data); + } + + public override void defineBits(DefineBits tag) + { + encodeTagHeader(tag.code, 2 + tag.data.Length, true); + int id = dict.add(tag); + writer.writeUI16(id); + writer.write(tag.data); + } + + public override void defineBitsJPEG2(DefineBits tag) + { + defineBits(tag); + } + + public override void defineBitsJPEG3(DefineBitsJPEG3 tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + tagw.write32(tag.data.Length); + tagw.write(tag.data); + tagw.markComp(); + tagw.write(tag.alphaData); + encodeTag(tag); + } + + public override void defineBitsLossless(DefineBitsLossless tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + tagw.writeUI8(tag.format); + tagw.writeUI16(tag.width); + tagw.writeUI16(tag.height); + switch (tag.format) + { + + case 3: + tagw.writeUI8(tag.colorData.Length - 1); + tagw.markComp(); + encodeColorMapData(tag.colorData, tag.data, tagw); + break; + + case 4: + case 5: + tagw.markComp(); + encodeBitmapData(tag.data, tagw); + break; + } + encodeTag(tag); + } + + private void encodeBitmapData(sbyte[] data, SwfEncoder w) + { + w.write(data); + } + + private void encodeColorMapData(int[] colorData, sbyte[] pixelData, SwfEncoder w) + { + for (int i = 0; i < colorData.Length; i++) + { + encodeRGB(colorData[i], w); + } + w.write(pixelData); + } + + /// as 0x00RRGGBB + /// + /// + /// + private void encodeRGB(int rgb, SwfEncoder w) + { + w.writeUI8(SupportClass.URShift(rgb, 16)); // red. we don't mask this because if rgb has an Alpha value, something's wrong + w.writeUI8((SupportClass.URShift(rgb, 8)) & 255); + w.writeUI8(rgb & 255); // blue + } + + public override void defineBitsLossless2(DefineBitsLossless tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + tagw.writeUI8(tag.format); + tagw.writeUI16(tag.width); + tagw.writeUI16(tag.height); + switch (tag.format) + { + + case 3: + tagw.writeUI8(tag.colorData.Length - 1); + tagw.markComp(); + encodeAlphaColorMapData(tag.colorData, tag.data, tagw); + break; + + case 4: + case 5: + tagw.markComp(); + encodeBitmapData(tag.data, tagw); + break; + } + encodeTag(tag); + } + + private void encodeAlphaColorMapData(int[] colorData, sbyte[] pixelData, SwfEncoder w) + { + for (int i = 0; i < colorData.Length; i++) + { + encodeRGBA(colorData[i], w); + } + w.write(pixelData); + } + + /// as 0xAARRGGBB + /// + /// + /// + private void encodeRGBA(int rgba, SwfEncoder w) + { + w.writeUI8((SupportClass.URShift(rgba, 16)) & 255); // red + w.writeUI8((SupportClass.URShift(rgba, 8)) & 255); // green + w.writeUI8(rgba & 255); // blue + w.writeUI8(SupportClass.URShift(rgba, 24)); // alpha + } + + public override void defineButton(DefineButton tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + + if (Debug) + { + debug.adjust = writer.Pos + 6; + } + + for (int i = 0; i < tag.buttonRecords.Length; i++) + { + encodeButtonRecord(tag.buttonRecords[i], tagw, tag.code); + } + tagw.writeUI8(0); // no more button records + + // assume there is only one condition we will handle + new ActionEncoder(tagw, debug).encode(tag.condActions[0].actionList); + tagw.writeUI8(0); // write action end flag, must be zero + encodeTag(tag); + + if (Debug) + { + debug.adjust = 0; + } + } + + private void encodeButtonRecord(ButtonRecord record, SwfEncoder w, int defineButton) + { + if (defineButton == flash.swf.TagValues_Fields.stagDefineButton2) + { + w.writeUBits(0, 2); + w.writeBit(record.blendMode != - 1); + w.writeBit(record.filters != null); + } + else + { + w.writeUBits(0, 4); + } + w.writeBit(record.hitTest); + w.writeBit(record.down); + w.writeBit(record.over); + w.writeBit(record.up); + + w.writeUI16(dict.getId(record.characterRef)); + w.writeUI16(record.placeDepth); + encodeMatrix(record.placeMatrix, w); + + if (defineButton == flash.swf.TagValues_Fields.stagDefineButton2) + { + encodeCxforma(record.colorTransform, w); + if (record.filters != null) + { + this.encodeFilterList(record.filters, w); + } + if (record.blendMode != - 1) + { + w.writeUI8(record.blendMode); + } + } + } + + private void encodeCxforma(CXFormWithAlpha cxforma, SwfEncoder w) + { + w.writeBit(cxforma.hasAdd); + w.writeBit(cxforma.hasMult); + + int nbits = cxforma.nbits(); + w.writeUBits(nbits, 4); + + if (cxforma.hasMult) + { + w.writeSBits(cxforma.redMultTerm, nbits); + w.writeSBits(cxforma.greenMultTerm, nbits); + w.writeSBits(cxforma.blueMultTerm, nbits); + w.writeSBits(cxforma.alphaMultTerm, nbits); + } + + if (cxforma.hasAdd) + { + w.writeSBits(cxforma.redAddTerm, nbits); + w.writeSBits(cxforma.greenAddTerm, nbits); + w.writeSBits(cxforma.blueAddTerm, nbits); + w.writeSBits(cxforma.alphaAddTerm, nbits); + } + + w.flushBits(); + } + + private void encodeMatrix(Matrix matrix, SwfEncoder w) + { + w.writeBit(matrix.hasScale); + if (matrix.hasScale) + { + int nScaleBits = matrix.nScaleBits(); + w.writeUBits(nScaleBits, 5); + w.writeSBits(matrix.scaleX, nScaleBits); + w.writeSBits(matrix.scaleY, nScaleBits); + } + + w.writeBit(matrix.hasRotate); + if (matrix.hasRotate) + { + int nRotateBits = matrix.nRotateBits(); + w.writeUBits(nRotateBits, 5); + w.writeSBits(matrix.rotateSkew0, nRotateBits); + w.writeSBits(matrix.rotateSkew1, nRotateBits); + } + + int nTranslateBits = matrix.nTranslateBits(); + w.writeUBits(nTranslateBits, 5); + w.writeSBits(matrix.translateX, nTranslateBits); + w.writeSBits(matrix.translateY, nTranslateBits); + + w.flushBits(); + } + + public override void defineButton2(DefineButton tag) + { + if (Debug) + { + debug.adjust = writer.Pos + 6; + } + + int id = dict.add(tag); + tagw.writeUI16(id); + tagw.writeUBits(0, 7); // reserved + tagw.writeBit(tag.trackAsMenu); + int offsetPos = tagw.Pos; + tagw.writeUI16(0); // actionOffset + + for (int i = 0; i < tag.buttonRecords.Length; i++) + { + encodeButtonRecord(tag.buttonRecords[i], tagw, tag.code); + } + + tagw.writeUI8(0); // charEndFlag + + if (tag.condActions.Length > 0) + { + tagw.writeUI16at(offsetPos, tagw.Pos - offsetPos); + + for (int i = 0; i < tag.condActions.Length; i++) + { + bool isLast = i + 1 == tag.condActions.Length; + encodeButtonCondAction(tag.condActions[i], tagw, isLast); + } + } + encodeTag(tag); + + if (Debug) + { + debug.adjust = 0; + } + } + + private void encodeButtonCondAction(ButtonCondAction condAction, SwfEncoder w, bool last) + { + int pos = w.Pos; + w.writeUI16(0); + + w.writeUBits(condAction.keyPress, 7); + w.writeBit(condAction.overDownToIdle); + + w.writeBit(condAction.idleToOverDown); + w.writeBit(condAction.outDownToIdle); + w.writeBit(condAction.outDownToOverDown); + w.writeBit(condAction.overDownToOutDown); + w.writeBit(condAction.overDownToOverUp); + w.writeBit(condAction.overUpToOverDown); + w.writeBit(condAction.overUpToIdle); + w.writeBit(condAction.idleToOverUp); + + new ActionEncoder(w, debug).encode(condAction.actionList); + w.writeUI8(0); // end action byte + + if (!last) + { + w.writeUI16at(pos, w.Pos - pos); + } + } + + public override void defineButtonCxform(DefineButtonCxform tag) + { + int idref = dict.getId(tag.button); + tagw.writeUI16(idref); + encodeCxform(tag.colorTransform, tagw); + encodeTag(tag); + } + + private void encodeCxform(CXForm cxform, SwfEncoder w) + { + + w.writeBit(cxform.hasAdd); + w.writeBit(cxform.hasMult); + + int nbits = cxform.nbits(); + w.writeUBits(nbits, 4); + + if (cxform.hasMult) + { + w.writeSBits(cxform.redMultTerm, nbits); + w.writeSBits(cxform.greenMultTerm, nbits); + w.writeSBits(cxform.blueMultTerm, nbits); + } + + if (cxform.hasAdd) + { + w.writeSBits(cxform.redAddTerm, nbits); + w.writeSBits(cxform.greenAddTerm, nbits); + w.writeSBits(cxform.blueAddTerm, nbits); + } + + w.flushBits(); + } + + public override void defineButtonSound(DefineButtonSound tag) + { + int idref = dict.getId(tag.button); + tagw.writeUI16(idref); + if (tag.sound0 != null) + { + tagw.writeUI16(dict.getId(tag.sound0)); + encodeSoundInfo(tag.info0, tagw); + } + else + { + tagw.writeUI16(0); + } + if (tag.sound1 != null) + { + tagw.writeUI16(dict.getId(tag.sound1)); + encodeSoundInfo(tag.info1, tagw); + } + else + { + tagw.writeUI16(0); + } + if (tag.sound2 != null) + { + tagw.writeUI16(dict.getId(tag.sound2)); + encodeSoundInfo(tag.info2, tagw); + } + else + { + tagw.writeUI16(0); + } + if (tag.sound3 != null) + { + tagw.writeUI16(dict.getId(tag.sound3)); + encodeSoundInfo(tag.info3, tagw); + } + else + { + tagw.writeUI16(0); + } + encodeTag(tag); + } + + private void encodeSoundInfo(SoundInfo info, SwfEncoder w) + { + w.writeUBits(0, 2); // reserved + w.writeBit(info.syncStop); + w.writeBit(info.syncNoMultiple); + w.writeBit(info.records != null); + w.writeBit(info.loopCount != SoundInfo.UNINITIALIZED); + w.writeBit(info.outPoint != SoundInfo.UNINITIALIZED); + w.writeBit(info.inPoint != SoundInfo.UNINITIALIZED); + + if (info.inPoint != SoundInfo.UNINITIALIZED) + { + w.write32((int) info.inPoint); + } + if (info.outPoint != SoundInfo.UNINITIALIZED) + { + w.write32((int) info.outPoint); + } + if (info.loopCount != SoundInfo.UNINITIALIZED) + { + w.writeUI16(info.loopCount); + } + if (info.records != null) + { + w.writeUI8(info.records.Length); + for (int k = 0; k < info.records.Length; k++) + { + w.write64(info.records[k]); + } + } + } + + public override void defineEditText(DefineEditText tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + encodeRect(tag.bounds, tagw); + + tagw.writeBit(tag.hasText); + tagw.writeBit(tag.wordWrap); + tagw.writeBit(tag.multiline); + tagw.writeBit(tag.password); + tagw.writeBit(tag.readOnly); + tagw.writeBit(tag.hasTextColor); + tagw.writeBit(tag.hasMaxLength); + tagw.writeBit(tag.hasFont); + + tagw.writeBit(false); // reserved + tagw.writeBit(tag.autoSize); + tagw.writeBit(tag.hasLayout); + tagw.writeBit(tag.noSelect); + tagw.writeBit(tag.border); + tagw.writeBit(tag.wasStatic); + tagw.writeBit(tag.html); + tagw.writeBit(tag.useOutlines); + + tagw.flushBits(); + + if (tag.hasFont) + { + int idref = dict.getId(tag.font); + tagw.writeUI16(idref); + tagw.writeUI16(tag.height); + } + + if (tag.hasTextColor) + { + encodeRGBA(tag.color, tagw); + } + + if (tag.hasMaxLength) + { + tagw.writeUI16(tag.maxLength); + } + + if (tag.hasLayout) + { + tagw.writeUI8(tag.align); + tagw.writeUI16(tag.leftMargin); + tagw.writeUI16(tag.rightMargin); + tagw.writeUI16(tag.ident); + tagw.writeSI16(tag.leading); // see errata, leading is signed + } + + tagw.writeString(tag.varName); + if (tag.hasText) + { + tagw.writeString(tag.initialText); + } + encodeTag(tag); + } + + public override void defineFont(DefineFont1 tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + + int count = tag.glyphShapeTable.Length; + + int offsetPos = tagw.Pos; + + // write offset placeholders + for (int i = 0; i < count; i++) + { + tagw.writeUI16(0); + } + + // now write glyphs and update the encoded offset table + for (int i = 0; i < count; i++) + { + tagw.writeUI16at(offsetPos + 2 * i, tagw.Pos - offsetPos); + encodeShape(tag.glyphShapeTable[i], tagw, flash.swf.TagValues_Fields.stagDefineShape3, 1, 0); + } + + encodeTag(tag); + } + + public virtual void encodeShape(Shape s, SwfEncoder w, int shape, int nFillStyles, int nLineStyles) + { + int[] numFillBits = new int[]{SwfEncoder.minBits(nFillStyles, 0)}; + int[] numLineBits = new int[]{SwfEncoder.minBits(nLineStyles, 0)}; + + w.writeUBits(numFillBits[0], 4); + w.writeUBits(numLineBits[0], 4); + + System.Collections.IEnumerator it = s.shapeRecords.GetEnumerator(); + //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" + while (it.MoveNext()) + { + //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" + ShapeRecord record = (ShapeRecord) it.Current; + if (record is StyleChangeRecord) + { + // style change + w.writeBit(false); + StyleChangeRecord change = (StyleChangeRecord) record; + encodeStyleChangeRecord(w, change, numFillBits, numLineBits, shape); + } + else + { + // edge + w.writeBit(true); + EdgeRecord e = (EdgeRecord) record; + bool straight = e is StraightEdgeRecord; + w.writeBit(straight); + int nbits = straight?calcBits((StraightEdgeRecord) e):calcBits((CurvedEdgeRecord) e); + if (nbits < 2) + nbits = 2; + w.writeUBits(nbits - 2, 4); + if (straight) + { + // line + StraightEdgeRecord line = (StraightEdgeRecord) e; + encodeStraightEdgeRecord(line, w, nbits); + } + else + { + // curve + CurvedEdgeRecord curve = (CurvedEdgeRecord) e; + w.writeSBits(curve.controlDeltaX, nbits); + w.writeSBits(curve.controlDeltaY, nbits); + w.writeSBits(curve.anchorDeltaX, nbits); + w.writeSBits(curve.anchorDeltaY, nbits); + } + } + } + + // endshaperecord + w.writeUBits(0, 6); + + w.flushBits(); + } + + private int calcBits(StraightEdgeRecord edge) + { + return SwfEncoder.minBits(SwfEncoder.maxNum(edge.deltaX, edge.deltaY, 0, 0), 1); + } + + private int calcBits(CurvedEdgeRecord edge) + { + return SwfEncoder.minBits(SwfEncoder.maxNum(edge.controlDeltaX, edge.controlDeltaY, edge.anchorDeltaX, edge.anchorDeltaY), 1); + } + + private void encodeStraightEdgeRecord(StraightEdgeRecord line, SwfEncoder w, int nbits) + { + if (line.deltaX == 0) + { + w.writeUBits(1, 2); // vertical line + w.writeSBits(line.deltaY, nbits); + } + else if (line.deltaY == 0) + { + w.writeUBits(0, 2); // horizontal line + w.writeSBits(line.deltaX, nbits); + } + else + { + w.writeBit(true); // general line + w.writeSBits(line.deltaX, nbits); + w.writeSBits(line.deltaY, nbits); + } + } + + private void encodeStyleChangeRecord(SwfEncoder w, StyleChangeRecord s, int[] numFillBits, int[] numLineBits, int shape) + { + w.writeBit(s.stateNewStyles); + w.writeBit(s.stateLineStyle); + w.writeBit(s.stateFillStyle1); + w.writeBit(s.stateFillStyle0); + w.writeBit(s.stateMoveTo); + + if (s.stateMoveTo) + { + int moveBits = s.nMoveBits(); + w.writeUBits(moveBits, 5); + w.writeSBits(s.moveDeltaX, moveBits); + w.writeSBits(s.moveDeltaY, moveBits); + } + + if (s.stateFillStyle0) + { + w.writeUBits(s.fillstyle0, numFillBits[0]); + } + + if (s.stateFillStyle1) + { + w.writeUBits(s.fillstyle1, numFillBits[0]); + } + + if (s.stateLineStyle) + { + w.writeUBits(s.linestyle, numLineBits[0]); + } + + if (s.stateNewStyles) + { + w.flushBits(); + + encodeFillstyles(s.fillstyles, w, shape); + encodeLinestyles(s.linestyles, w, shape); + + numFillBits[0] = SwfEncoder.minBits(s.fillstyles.Count, 0); + numLineBits[0] = SwfEncoder.minBits(s.linestyles.Count, 0); + w.writeUBits(numFillBits[0], 4); + w.writeUBits(numLineBits[0], 4); + } + } + + private void encodeLinestyles(System.Collections.ArrayList linestyles, SwfEncoder w, int shape) + { + int count = linestyles.Count; + if (count > 0xFF) + { + w.writeUI8(0xFF); + w.writeUI16(count); + } + else + { + w.writeUI8(count); + } + + for (int i = 0; i < count; i++) + { + encodeLineStyle((LineStyle) linestyles[i], w, shape); + } + } + + private void encodeLineStyle(LineStyle lineStyle, SwfEncoder w, int shape) + { + w.writeUI16(lineStyle.width); + + if (shape == flash.swf.TagValues_Fields.stagDefineShape6) + { + w.writeUI16(lineStyle.flags); + if (lineStyle.hasMiterJoint()) + w.writeUI16(lineStyle.miterLimit); + } + + if (shape == flash.swf.TagValues_Fields.stagDefineShape6 && lineStyle.hasFillStyle()) + { + encodeFillStyle(lineStyle.fillStyle, w, shape); + } + else if ((shape == flash.swf.TagValues_Fields.stagDefineShape3) || (shape == flash.swf.TagValues_Fields.stagDefineShape6)) + { + encodeRGBA(lineStyle.color, w); + } + else + { + encodeRGB(lineStyle.color, w); + } + } + + private void encodeFillstyles(System.Collections.ArrayList fillstyles, SwfEncoder w, int shape) + { + int count = fillstyles.Count; + if (count >= 0xFF) + { + w.writeUI8(0xFF); + w.writeUI16(count); + } + else + { + w.writeUI8(count); + } + + System.Collections.IEnumerator it = fillstyles.GetEnumerator(); + //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" + while (it.MoveNext()) + { + //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" + FillStyle style = (FillStyle) it.Current; + encodeFillStyle(style, w, shape); + } + } + + private void encodeFillStyle(FillStyle style, SwfEncoder w, int shape) + { + w.writeUI8(style.type); + switch (style.type) + { + + case FillStyle.FILL_SOLID: // 0x00 + if ((shape == flash.swf.TagValues_Fields.stagDefineShape3) || (shape == flash.swf.TagValues_Fields.stagDefineShape6)) + encodeRGBA(style.color, w); + else + encodeRGB(style.color, w); + break; + + case FillStyle.FILL_GRADIENT: + // 0x10 linear gradient fill + case FillStyle.FILL_RADIAL_GRADIENT: + // 0x12 radial gradient fill + case FillStyle.FILL_FOCAL_RADIAL_GRADIENT: // 0x13 focal radial gradient fill + encodeMatrix(style.matrix, w); + encodeGradient(style.gradient, w, shape); + break; + + case FillStyle.FILL_BITS: + // 0x40 tiled bitmap fill + case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP): + // 0x41 clipped bitmap fill + case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_NOSMOOTH): + // 0x42 tiled non-smoothed fill + case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP | FillStyle.FILL_BITS_NOSMOOTH): // 0x43 clipped non-smoothed fill + w.writeUI16(dict.getId(style.bitmap)); + encodeMatrix(style.matrix, w); + break; + } + } + + private void encodeGradient(Gradient gradient, SwfEncoder w, int shape) + { + w.writeUBits(gradient.spreadMode, 2); + w.writeUBits(gradient.interpolationMode, 2); + w.writeUBits(gradient.records.Length, 4); + for (int i = 0; i < gradient.records.Length; i++) + { + encodeGradRecord(gradient.records[i], w, shape); + } + if (gradient is FocalGradient) + { + w.writeFixed8(((FocalGradient) gradient).focalPoint); + } + } + + private void encodeGradRecord(GradRecord record, SwfEncoder w, int shape) + { + w.writeUI8(record.ratio); + if ((shape == flash.swf.TagValues_Fields.stagDefineShape3) || (shape == flash.swf.TagValues_Fields.stagDefineShape6)) + encodeRGBA(record.color, w); + else + encodeRGB(record.color, w); + } + + public override void defineFont2(DefineFont2 tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + int startPos = tagw.Pos; + bool again; + + if (tag.code == flash.swf.TagValues_Fields.stagDefineFont3) + { + tag.wideCodes = true; + } + + if (!tag.wideCodes) + { + for (int i = 0; i < tag.codeTable.Length; i++) + { + if (tag.codeTable[i] > 255) + { + tag.wideCodes = true; + break; + } + } + } + + //UPGRADE_NOTE: Label 'loop' was moved. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1014'" + do + { + again = false; + tagw.writeBit(tag.hasLayout); + tagw.writeBit(tag.shiftJIS); + tagw.writeBit(tag.smallText); + tagw.writeBit(tag.ansi); + tagw.writeBit(tag.wideOffsets); + tagw.writeBit(tag.wideCodes); + tagw.writeBit(tag.italic); + tagw.writeBit(tag.bold); + tagw.flushBits(); + + tagw.writeUI8(tag.langCode); + + tagw.writeLengthString(tag.fontName); + int count = tag.glyphShapeTable.Length; + + tagw.writeUI16(count); + int offsetPos = tagw.Pos; + + // save space for the offset table + if (tag.wideOffsets) + { + for (int i = 0; i < count; i++) + { + tagw.write32(0); + } + } + else + { + for (int i = 0; i < count; i++) + { + tagw.writeUI16(0); + } + } + + //PJF: write placeholder for codeTableOffset, this will be changed after shapes encoded + if (count > 0) + { + if (tag.wideOffsets) + { + tagw.write32(0); + } + else + { + tagw.writeUI16(0); + } + } + + for (int i = 0; i < count; i++) + { + // save offset to this glyph + int offset = tagw.Pos - offsetPos; + if (!tag.wideOffsets && offset > 65535) + { + again = true; + tag.wideOffsets = true; + tagw.Pos = startPos; + //UPGRADE_NOTE: Labeled continue statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1015'" + goto loop; + } + if (tag.wideOffsets) + tagw.write32at(offsetPos + 4 * i, offset); + else + tagw.writeUI16at(offsetPos + 2 * i, offset); + + encodeShape(tag.glyphShapeTable[i], tagw, flash.swf.TagValues_Fields.stagDefineShape3, 1, 0); + } + + // update codeTableOffset + int offset2 = tagw.Pos - offsetPos; + if (!tag.wideOffsets && offset2 > 65535) + { + again = true; + tag.wideOffsets = true; + tagw.Pos = startPos; + //UPGRADE_NOTE: Labeled continue statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1015'" + goto loop; + } + if (tag.wideOffsets) + { + tagw.write32at(offsetPos + 4 * count, offset2); + } + else + { + tagw.writeUI16at(offsetPos + 2 * count, offset2); + } + + // now write the codetable + + if (tag.wideCodes) + { + for (int i = 0; i < tag.codeTable.Length; i++) + { + tagw.writeUI16(tag.codeTable[i]); + } + } + else + { + for (int i = 0; i < tag.codeTable.Length; i++) + { + tagw.writeUI8(tag.codeTable[i]); + } + } + + if (tag.hasLayout) + { + tagw.writeSI16(tag.ascent); + tagw.writeSI16(tag.descent); + tagw.writeSI16(tag.leading); + + for (int i = 0; i < tag.advanceTable.Length; i++) + { + tagw.writeSI16(tag.advanceTable[i]); + } + + for (int i = 0; i < tag.boundsTable.Length; i++) + { + encodeRect(tag.boundsTable[i], tagw); + } + + tagw.writeUI16(tag.kerningTable.Length); + + for (int i = 0; i < tag.kerningTable.Length; i++) + { + if (!tag.wideCodes && ((tag.kerningTable[i].code1 > 255) || (tag.kerningTable[i].code2 > 255))) + { + again = true; + tag.wideCodes = true; + tagw.Pos = startPos; + //UPGRADE_NOTE: Labeled continue statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1015'" + goto loop; + } + + encodeKerningRecord(tag.kerningTable[i], tagw, tag.wideCodes); + } + } + //UPGRADE_NOTE: Label 'loop' was moved. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1014'" +loop: ; + } + while (again); + + encodeTag(tag); + } + + public override void defineFont3(DefineFont3 tag) + { + defineFont2(tag); + } + + public override void defineFont4(DefineFont4 tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + + tagw.writeUBits(0, 5); // reserved + tagw.writeBit(tag.hasFontData); + //tagw.writeBit(tag.smallText); + tagw.writeBit(tag.italic); + tagw.writeBit(tag.bold); + tagw.flushBits(); + + //tagw.writeUI8(tag.langCode); + tagw.writeString(tag.fontName); + if (tag.hasFontData) + { + tagw.write(tag.data); + } + + encodeTag(tag); + } + + public override void defineFontAlignZones(DefineFontAlignZones tag) + { + int fontID = dict.getId(tag.font); + tagw.writeUI16(fontID); + tagw.writeUBits(tag.csmTableHint, 2); + tagw.writeUBits(0, 6); // reserved + for (int i = 0; i < tag.zoneTable.Length; i++) + { + ZoneRecord record = tag.zoneTable[i]; + tagw.writeUI8(record.numZoneData); + for (int j = 0; j < record.numZoneData; j++) + { + tagw.write32((int) record.zoneData[j]); + } + tagw.writeUI8(record.zoneMask); + } + encodeTag(tag); + } + + public override void csmTextSettings(CSMTextSettings tag) + { + int textID = 0; + if (tag.textReference != null) + { + textID = dict.getId(tag.textReference); + } + tagw.writeUI16(textID); + tagw.writeUBits(tag.styleFlagsUseSaffron, 2); + tagw.writeUBits(tag.gridFitType, 3); + tagw.writeUBits(0, 3); // reserved + // FIXME: thickness/sharpness should be written out as 32 bit IEEE Single Precision format in little Endian + tagw.writeUBits((int) tag.thickness, 32); + tagw.writeUBits((int) tag.sharpness, 32); + tagw.writeUBits(0, 8); //reserved + + encodeTag(tag); + } + + public override void defineFontName(DefineFontName tag) + { + int fontID = dict.getId(tag.font); + tagw.writeUI16(fontID); + if (tag.fontName != null) + { + tagw.writeString(tag.fontName); + } + else + { + tagw.writeString(""); + } + if (tag.copyright != null) + { + tagw.writeString(tag.copyright); + } + else + { + tagw.writeString(""); + } + + encodeTag(tag); + } + + private void encodeKerningRecord(KerningRecord kerningRecord, SwfEncoder w, bool wideCodes) + { + if (wideCodes) + { + w.writeUI16(kerningRecord.code1); + w.writeUI16(kerningRecord.code2); + } + else + { + w.writeUI8(kerningRecord.code1); + w.writeUI8(kerningRecord.code2); + } + w.writeUI16(kerningRecord.adjustment); + } + + public override void defineFontInfo(DefineFontInfo tag) + { + int idref = dict.getId(tag.font); + tagw.writeUI16(idref); + + tagw.writeLengthString(tag.name); + + tagw.writeUBits(0, 3); // reserved + tagw.writeBit(tag.shiftJIS); + tagw.writeBit(tag.ansi); + tagw.writeBit(tag.italic); + tagw.writeBit(tag.bold); + + if (tag.code == flash.swf.TagValues_Fields.stagDefineFontInfo2) + { + tagw.writeBit(tag.wideCodes = true); + tagw.writeUI8(tag.langCode); + } + else + { + if (!tag.wideCodes) + { + for (int i = 0; i < tag.codeTable.Length; i++) + { + if (tag.codeTable[i] > 255) + { + tag.wideCodes = true; + break; + } + } + } + tagw.writeBit(tag.wideCodes); + } + + if (tag.wideCodes) + { + for (int i = 0; i < tag.codeTable.Length; i++) + tagw.writeUI16(tag.codeTable[i]); + } + else + { + for (int i = 0; i < tag.codeTable.Length; i++) + tagw.writeUI8(tag.codeTable[i]); + } + encodeTag(tag); + } + + public override void defineFontInfo2(DefineFontInfo tag) + { + defineFontInfo(tag); + } + + public override void defineMorphShape(DefineMorphShape tag) + { + defineMorphShape2(tag); + } + + public override void defineMorphShape2(DefineMorphShape tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + encodeRect(tag.startBounds, tagw); + encodeRect(tag.endBounds, tagw); + if (tag.code == flash.swf.TagValues_Fields.stagDefineMorphShape2) + { + encodeRect(tag.startEdgeBounds, tagw); + encodeRect(tag.endEdgeBounds, tagw); + tagw.writeUBits(tag.reserved, 6); + tagw.writeUBits(tag.usesNonScalingStrokes?1:0, 1); + tagw.writeUBits(tag.usesScalingStrokes?1:0, 1); + } + tagw.write32(0); + int pos = tagw.Pos; + encodeMorphFillstyles(tag.fillStyles, tagw, tag.code); + encodeMorphLinestyles(tag.lineStyles, tagw, tag.code); + encodeShape(tag.startEdges, tagw, flash.swf.TagValues_Fields.stagDefineShape3, tag.fillStyles.Length, tag.lineStyles.Length); + tagw.write32at(pos - 4, tagw.Pos - pos); + // end shape contains only edges, no style information + encodeShape(tag.endEdges, tagw, flash.swf.TagValues_Fields.stagDefineShape3, 0, 0); + encodeTag(tag); + } + + private void encodeMorphFillstyles(MorphFillStyle[] fillStyles, SwfEncoder w, int code) + { + int count = fillStyles.Length; + if (count >= 0xFF) + { + w.writeUI8(0xFF); + w.writeUI16(count); + } + else + { + w.writeUI8(count); + } + + for (int i = 0; i < count; i++) + { + encodeMorphFillstyle(fillStyles[i], w, code); + } + } + + private void encodeMorphFillstyle(MorphFillStyle style, SwfEncoder w, int code) + { + w.writeUI8(style.type); + switch (style.type) + { + + case FillStyle.FILL_SOLID: // 0x00 + encodeRGBA(style.startColor, w); + encodeRGBA(style.endColor, w); + break; + + case FillStyle.FILL_GRADIENT: + // 0x10 linear gradient fill + case FillStyle.FILL_RADIAL_GRADIENT: + // 0x12 radial gradient fill + case FillStyle.FILL_FOCAL_RADIAL_GRADIENT: // 0x13 focal radial gradient fill + encodeMatrix(style.startGradientMatrix, w); + encodeMatrix(style.endGradientMatrix, w); + encodeMorphGradient(style.gradRecords, w); + if (style.type == FillStyle.FILL_FOCAL_RADIAL_GRADIENT && code == flash.swf.TagValues_Fields.stagDefineMorphShape2) + { + w.writeSI16(style.ratio1); + w.writeSI16(style.ratio2); + } + break; + + case FillStyle.FILL_BITS: + // 0x40 tiled bitmap fill + case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP): + // 0x41 clipped bitmap fill + case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_NOSMOOTH): + // 0x42 tiled non-smoothed fill + case (FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP | FillStyle.FILL_BITS_NOSMOOTH): // 0x43 clipped non-smoothed fill + w.writeUI16(dict.getId(style.bitmap)); + encodeMatrix(style.startBitmapMatrix, w); + encodeMatrix(style.endBitmapMatrix, w); + break; + + default: + assert(false); + //throw new IOException("unrecognized fill style type: " + style.type); + break; + + } + } + + private void encodeMorphGradient(MorphGradRecord[] gradRecords, SwfEncoder w) + { + w.writeUI8(gradRecords.Length); + for (int i = 0; i < gradRecords.Length; i++) + { + MorphGradRecord record = gradRecords[i]; + w.writeUI8(record.startRatio); + encodeRGBA(record.startColor, w); + w.writeUI8(record.endRatio); + encodeRGBA(record.endColor, w); + } + } + + private void encodeMorphLinestyles(MorphLineStyle[] lineStyles, SwfEncoder w, int code) + { + if (lineStyles.Length >= 0xFF) + { + w.writeUI8(0xFF); + w.writeUI16(lineStyles.Length); + } + else + { + w.writeUI8(lineStyles.Length); + } + + for (int i = 0; i < lineStyles.Length; i++) + { + MorphLineStyle style = lineStyles[i]; + w.writeUI16(style.startWidth); + w.writeUI16(style.endWidth); + if (code == flash.swf.TagValues_Fields.stagDefineMorphShape2) + { + w.writeUBits(style.startCapsStyle, 2); + w.writeUBits(style.jointStyle, 2); + w.writeBit(style.hasFill); + w.writeBit(style.noHScale); + w.writeBit(style.noVScale); + w.writeBit(style.pixelHinting); + w.writeUBits(0, 5); // reserved + w.writeBit(style.noClose); + w.writeUBits(style.endCapsStyle, 2); + if (style.jointStyle == 2) + { + w.writeUI16(style.miterLimit); + } + } + if (!style.hasFill) + { + encodeRGBA(style.startColor, w); + encodeRGBA(style.endColor, w); + } + if (style.hasFill) + { + encodeMorphFillstyle(style.fillType, w, code); + } + } + } + + public override void defineShape(DefineShape tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + encodeRect(tag.bounds, tagw); + if (tag.code == flash.swf.TagValues_Fields.stagDefineShape6) + { + encodeRect(tag.edgeBounds, tagw); + tagw.writeUBits(0, 6); + tagw.writeBit(tag.usesNonScalingStrokes); + tagw.writeBit(tag.usesScalingStrokes); + } + encodeShapeWithStyle(tag.shapeWithStyle, tagw, tag.code); + encodeTag(tag); + } + + private void encodeShapeWithStyle(ShapeWithStyle shapeWithStyle, SwfEncoder w, int shape) + { + encodeFillstyles(shapeWithStyle.fillstyles, w, shape); + encodeLinestyles(shapeWithStyle.linestyles, w, shape); + + encodeShape(shapeWithStyle, w, shape, shapeWithStyle.fillstyles.Count, shapeWithStyle.linestyles.Count); + } + + public override void defineShape2(DefineShape tag) + { + defineShape(tag); + } + + public override void defineShape3(DefineShape tag) + { + defineShape(tag); + } + + public override void defineShape6(DefineShape tag) + { + defineShape(tag); + } + + public override void defineSound(DefineSound tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + tagw.writeUBits(tag.format, 4); + tagw.writeUBits(tag.rate, 2); + tagw.writeUBits(tag.size, 1); + tagw.writeUBits(tag.type, 1); + tagw.write32((int) tag.sampleCount); + tagw.write(tag.data); + encodeTag(tag); + } + + public override void defineSprite(DefineSprite tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + tagw.writeUI16(tag.framecount); + + if (Debug) + { + debug.adjust = writer.Pos + 6; + } + + // save frame count + int oldFrames = frames; + frames = 0; + + // save the movie writer, and push a new writer + SwfEncoder oldWriter = writer; + writer = tagw; + tagw = createEncoder(SwfVersion); + + // write sprite tags + System.Collections.IList tags = tag.tagList.tags; + int size = tags.Count; + for (int i = 0; i < size; i++) + { + Tag t = (Tag) tags[i]; + if (!(t is DefineTag)) + t.visit(this); + } + + // terminate with end marker + writer.writeUI16(0); + + // update frame count + writer.writeUI16at(2, frames); + + // restore writers + tagw = writer; + writer = oldWriter; + frames = oldFrames; + + if (Debug) + { + debug.adjust = 0; + } + + encodeTag(tag); + } + + public override void defineText(DefineText tag) + { + encodeDefineText(tag, tagw, tag.code); + encodeTag(tag); + } + + private void encodeDefineText(DefineText tag, SwfEncoder w, int type) + { + int id = dict.add(tag); + w.writeUI16(id); + encodeRect(tag.bounds, w); + encodeMatrix(tag.matrix, w); + int length = tag.records.Count; + + // compute necessary bit width + int glyphBits = 0; + int advanceBits = 0; + for (int i = 0; i < length; i++) + { + TextRecord tr = (TextRecord) tag.records[i]; + + for (int j = 0; j < tr.entries.Length; j++) + { + GlyphEntry entry = tr.entries[j]; + + while (entry.Index > (1 << glyphBits)) + glyphBits++; + while (System.Math.Abs(entry.advance) > (1 << advanceBits)) + advanceBits++; + } + } + + // increment to get from bit index to bit count. + ++glyphBits; + ++advanceBits; + + w.writeUI8(glyphBits); + w.writeUI8(++advanceBits); // add one extra bit because advances are signed + + for (int i = 0; i < length; i++) + { + TextRecord record = (TextRecord) tag.records[i]; + encodeTextRecord(record, w, type, glyphBits, advanceBits); + } + + w.writeUI8(0); + } + + private void encodeFilterList(System.Collections.IList filters, SwfEncoder w) + { + int count = filters.Count; + w.writeUI8(count); + //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" + for (System.Collections.IEnumerator it = filters.GetEnumerator(); it.MoveNext(); ) + { + //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" + Filter f = (Filter) it.Current; + w.writeUI8(f.getID()); + // I've never quite understood why the serialization code isn't in the tags themselves.. + switch (f.getID()) + { + + case DropShadowFilter.ID: encodeDropShadowFilter(w, (DropShadowFilter) f); break; + + case BlurFilter.ID: encodeBlurFilter(w, (BlurFilter) f); break; + + case ConvolutionFilter.ID: encodeConvolutionFilter(w, (ConvolutionFilter) f); break; + + case GlowFilter.ID: encodeGlowFilter(w, (GlowFilter) f); break; + + case BevelFilter.ID: encodeBevelFilter(w, (BevelFilter) f); break; + + case ColorMatrixFilter.ID: encodeColorMatrixFilter(w, (ColorMatrixFilter) f); break; + + case GradientGlowFilter.ID: encodeGradientGlowFilter(w, (GradientGlowFilter) f); break; + + case GradientBevelFilter.ID: encodeGradientBevelFilter(w, (GradientBevelFilter) f); break; + } + } + } + + private void encodeDropShadowFilter(SwfEncoder w, DropShadowFilter f) + { + encodeRGBA(f.color, w); + w.write32(f.blurX); + w.write32(f.blurY); + w.write32(f.angle); + w.write32(f.distance); + w.writeUI16(f.strength); + w.writeUI8(f.flags); + } + + private void encodeBlurFilter(SwfEncoder w, BlurFilter f) + { + w.write32(f.blurX); + w.write32(f.blurY); + w.writeUI8(f.passes); + } + private void encodeColorMatrixFilter(SwfEncoder w, ColorMatrixFilter f) + { + for (int i = 0; i < 20; ++i) + { + w.writeFloat(f.values[i]); + } + } + private void encodeConvolutionFilter(SwfEncoder w, ConvolutionFilter f) + { + w.writeUI8(f.matrixX); + w.writeUI8(f.matrixY); + w.writeFloat(f.divisor); + w.writeFloat(f.bias); + for (int i = 0; i < f.matrix.Length; ++i) + w.writeFloat(f.matrix[i]); + w.writeUI8(f.flags); + } + private void encodeGlowFilter(SwfEncoder w, GlowFilter f) + { + encodeRGBA(f.color, w); + w.write32(f.blurX); + w.write32(f.blurY); + w.writeUI16(f.strength); + w.writeUI8(f.flags); + } + private void encodeBevelFilter(SwfEncoder w, BevelFilter f) + { + encodeRGBA(f.shadowColor, w); + encodeRGBA(f.highlightColor, w); + w.write32(f.blurX); + w.write32(f.blurY); + w.write32(f.angle); + w.write32(f.distance); + w.writeUI16(f.strength); + w.writeUI8(f.flags); + } + + private void encodeGradientGlowFilter(SwfEncoder w, GradientGlowFilter f) + { + w.writeUI8(f.numcolors); + for (int i = 0; i < f.numcolors; ++i) + encodeRGBA(f.gradientColors[i], w); + for (int i = 0; i < f.numcolors; ++i) + w.writeUI8(f.gradientRatio[i]); + //w.write32( f.color ); + w.write32(f.blurX); + w.write32(f.blurY); + w.write32(f.angle); + w.write32(f.distance); + w.writeUI16(f.strength); + w.writeUI8(f.flags); + } + private void encodeGradientBevelFilter(SwfEncoder w, GradientBevelFilter f) + { + w.writeUI8(f.numcolors); + for (int i = 0; i < f.numcolors; ++i) + encodeRGBA(f.gradientColors[i], w); + for (int i = 0; i < f.numcolors; ++i) + w.writeUI8(f.gradientRatio[i]); + + // w.write32( f.shadowColor ); + // w.write32( f.highlightColor ); + w.write32(f.blurX); + w.write32(f.blurY); + w.write32(f.angle); + w.write32(f.distance); + w.writeUI16(f.strength); + w.writeUI8(f.flags); + } + + private void encodeTextRecord(TextRecord record, SwfEncoder w, int type, int glyphBits, int advanceBits) + { + w.writeUI8(record.flags); + + if (record.hasFont()) + { + w.writeUI16(dict.getId(record.font)); + } + + if (record.hasColor()) + { + if (type == flash.swf.TagValues_Fields.stagDefineText2) + encodeRGBA(record.color, w); + else + encodeRGB(record.color, w); + } + + if (record.hasX()) + { + w.writeSI16(record.xOffset); + } + + if (record.hasY()) + { + w.writeSI16(record.yOffset); + } + + if (record.hasHeight()) + { + w.writeUI16(record.height); + } + + w.writeUI8(record.entries.Length); + + for (int i = 0; i < record.entries.Length; i++) + { + w.writeUBits(record.entries[i].Index, glyphBits); + w.writeSBits(record.entries[i].advance, advanceBits); + } + w.flushBits(); + } + + public override void defineText2(DefineText tag) + { + defineText(tag); + } + + public override void defineVideoStream(DefineVideoStream tag) + { + int id = dict.add(tag); + tagw.writeUI16(id); + tagw.writeUI16(tag.numFrames); + tagw.writeUI16(tag.width); + tagw.writeUI16(tag.height); + + tagw.writeUBits(0, 4); // reserved + tagw.writeUBits(tag.deblocking, 3); + tagw.writeBit(tag.smoothing); + + tagw.writeUI8(tag.codecID); + encodeTag(tag); + } + + public override void doAction(DoAction tag) + { + int adjust = 0; + if (Debug) + { + adjust = writer.Pos + 6; + debug.adjust += adjust; + } + + new ActionEncoder(tagw, debug).encode(tag.actionList); + tagw.writeUI8(0); + encodeTag(tag); + + if (Debug) + { + debug.adjust -= adjust; + } + } + + public override void doInitAction(DoInitAction tag) + { + int adjust = 0; + if (Debug) + { + adjust = writer.Pos + 6; + debug.adjust += adjust; + } + + int idref = dict.getId(tag.sprite); + tagw.writeUI16(idref); + new ActionEncoder(tagw, debug).encode(tag.actionList); + tagw.writeUI8(0); + encodeTag(tag); + + if (Debug) + { + debug.adjust -= adjust; + } + } + + public override void enableDebugger(EnableDebugger tag) + { + tagw.writeString(tag.password); + encodeTag(tag); + } + + public override void enableDebugger2(EnableDebugger tag) + { + // This corresponds to the constant used in the player, + // core/splay.cpp, in ScriptThread::EnableDebugger(). + tagw.writeUI16(0x1975); + tagw.writeString(tag.password); + encodeTag(tag); + } + + public override void exportAssets(ExportAssets tag) + { + tagw.writeUI16(tag.exports.Count); + System.Collections.IEnumerator it = tag.exports.GetEnumerator(); + //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" + while (it.MoveNext()) + { + //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" + DefineTag ref_Renamed = (DefineTag) it.Current; + int idref = dict.getId(ref_Renamed); + tagw.writeUI16(idref); + assert(ref_Renamed.name != null); // exported symbols must have names + tagw.writeString(ref_Renamed.name); + dict.addName(ref_Renamed, ref_Renamed.name); + } + encodeTag(tag); + } + + public override void symbolClass(SymbolClass tag) + { + tagw.writeUI16(tag.class2tag.Count + (tag.topLevelClass != null?1:0)); + //UPGRADE_TODO: Method 'java.util.Map.entrySet' was converted to 'SupportClass.HashSetSupport' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilMapentrySet'" + System.Collections.IEnumerator it = new SupportClass.HashSetSupport(tag.class2tag).GetEnumerator(); + //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" + while (it.MoveNext()) + { + //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" + System.Collections.DictionaryEntry e = (System.Collections.DictionaryEntry) it.Current; + System.String name = (System.String) e.Key; + DefineTag ref_Renamed = (DefineTag) e.Value; + + int idref = dict.getId(ref_Renamed); + tagw.writeUI16(idref); + tagw.writeString(name); + } + if (tag.topLevelClass != null) + { + tagw.writeUI16(0); + tagw.writeString(tag.topLevelClass); + } + encodeTag(tag); + } + + public override void frameLabel(FrameLabel tag) + { + tagw.writeString(tag.label); + if (tag.anchor && SwfVersion >= 6) + { + tagw.writeUI8(1); + } + encodeTag(tag); + } + + public override void importAssets(ImportAssets tag) + { + tagw.writeString(tag.url); + if (tag.code == flash.swf.TagValues_Fields.stagImportAssets2) + { + tagw.writeUI8(tag.downloadNow?1:0); + tagw.writeUI8(tag.SHA1 != null?1:0); + if (tag.SHA1 != null) + { + tagw.write(tag.SHA1); + } + } + tagw.writeUI16(tag.importRecords.Count); + System.Collections.IEnumerator it = tag.importRecords.GetEnumerator(); + //UPGRADE_TODO: Method 'java.util.Iterator.hasNext' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratorhasNext'" + while (it.MoveNext()) + { + //UPGRADE_TODO: Method 'java.util.Iterator.next' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilIteratornext'" + ImportRecord record = (ImportRecord) it.Current; + int id = dict.add(record); + tagw.writeUI16(id); + tagw.writeString(record.name); + } + encodeTag(tag); + } + + public override void importAssets2(ImportAssets tag) + { + importAssets(tag); + } + + public override void jpegTables(GenericTag tag) + { + encodeTagHeader(tag.code, tag.data.Length, false); + writer.write(tag.data); + } + + public override void placeObject(PlaceObject tag) + { + int idref = dict.getId(tag.ref_Renamed); + tagw.writeUI16(idref); + tagw.writeUI16(tag.depth); + encodeMatrix(tag.matrix, tagw); + if (tag.colorTransform != null) + { + encodeCxform(tag.colorTransform, tagw); + } + encodeTag(tag); + } + + public override void placeObject2(PlaceObject tag) + { + placeObject23(tag); + } + + public override void placeObject3(PlaceObject tag) + { + placeObject23(tag); + } + + public virtual void placeObject23(PlaceObject tag) + { + tagw.writeUI8(tag.flags); + if (tag.code == flash.swf.TagValues_Fields.stagPlaceObject3) + { + tagw.writeUI8(tag.flags2); + } + tagw.writeUI16(tag.depth); + if (tag.hasClassName()) + { + tagw.writeString(tag.className); + } + if (tag.hasCharID()) + { + int idref = dict.getId(tag.ref_Renamed); + tagw.writeUI16(idref); + } + if (tag.hasMatrix()) + { + encodeMatrix(tag.matrix, tagw); + } + if (tag.hasCxform()) + { + // ed 5/22/03 the SWF 6 file format spec says this should be a CXFORM, but + // the spec is wrong. the player expects a CXFORMA. + encodeCxforma(((CXFormWithAlpha) tag.colorTransform), tagw); + } + if (tag.hasRatio()) + { + tagw.writeUI16(tag.ratio); + } + if (tag.hasName()) + { + tagw.writeString(tag.name); + } + if (tag.hasClipDepth()) + { + tagw.writeUI16(tag.clipDepth); + } + if (tag.code == flash.swf.TagValues_Fields.stagPlaceObject3) + { + if (tag.hasFilterList()) + { + encodeFilterList(tag.filters, tagw); + } + if (tag.hasBlendMode()) + { + tagw.writeUI8(tag.blendMode); + } + } + if (tag.hasClipAction()) + { + int adjust = 0; + if (Debug) + { + adjust = writer.Pos + 6; + debug.adjust += adjust; + } + new ActionEncoder(tagw, debug).encodeClipActions(tag.clipActions); + if (Debug) + { + debug.adjust -= adjust; + } + } + encodeTag(tag); + } + + public override void protect(GenericTag tag) + { + if (tag.data != null) + { + encodeTagHeader(tag.code, tag.data.Length, false); + writer.write(tag.data); + } + else + { + encodeTagHeader(tag.code, 0, false); + } + } + + public override void removeObject(RemoveObject tag) + { + encodeTagHeader(tag.code, 4, false); + int idref = dict.getId(tag.ref_Renamed); + writer.writeUI16(idref); + writer.writeUI16(tag.depth); + } + + public override void removeObject2(RemoveObject tag) + { + encodeTagHeader(tag.code, 2, false); + writer.writeUI16(tag.depth); + } + + public override void showFrame(ShowFrame tag) + { + encodeTagHeader(tag.code, 0, false); + frames++; + } + + public override void soundStreamBlock(GenericTag tag) + { + encodeTagHeader(tag.code, tag.data.Length, false); + writer.write(tag.data); + } + + public override void soundStreamHead(SoundStreamHead tag) + { + int length = 4; + + // we need to add two bytes for an extra SI16 (latencySeek) + if (tag.compression == SoundStreamHead.sndCompressMP3) + { + length += 2; + } + + encodeTagHeader(tag.code, length, false); + + // 1 byte + writer.writeUBits(0, 4); // reserved + writer.writeUBits(tag.playbackRate, 2); + writer.writeUBits(tag.playbackSize, 1); + writer.writeUBits(tag.playbackType, 1); + + // 1 byte + writer.writeUBits(tag.compression, 4); + writer.writeUBits(tag.streamRate, 2); + writer.writeUBits(tag.streamSize, 1); + writer.writeUBits(tag.streamType, 1); + + // 2 bytes + writer.writeUI16(tag.streamSampleCount); + + if (tag.compression == SoundStreamHead.sndCompressMP3) + { + // 2 bytes + writer.writeSI16(tag.latencySeek); + } + } + + public override void soundStreamHead2(SoundStreamHead tag) + { + soundStreamHead(tag); + } + + public override void startSound(StartSound tag) + { + int idref = dict.getId(tag.sound); + tagw.writeUI16(idref); + encodeSoundInfo(tag.soundInfo, tagw); + encodeTag(tag); + } + + public override void videoFrame(VideoFrame tag) + { + encodeTagHeader(tag.code, 4 + tag.videoData.Length, false); + int idref = dict.getId(tag.stream); + writer.writeUI16(idref); + writer.writeUI16(tag.frameNum); + writer.write(tag.videoData); + } + + public override void defineSceneAndFrameLabelData(DefineSceneAndFrameLabelData tag) + { + encodeTagHeader(tag.code, tag.data.Length, false); + writer.write(tag.data); + } + + public override void doABC(DoABC tag) + { + if (tag.code == flash.swf.TagValues_Fields.stagDoABC2) + { + encodeTagHeader(tag.code, 4 + tag.name.Length + 1 + tag.abc.Length, false); + writer.write32(tag.flag); + writer.writeString(tag.name); + } + else + { + encodeTagHeader(tag.code, tag.abc.Length, false); + } + + writer.write(tag.abc); + } + + public override void unknown(GenericTag tag) + { + encodeTagHeader(tag.code, tag.data.Length, false); + writer.write(tag.data); + } + + public virtual sbyte[] toByteArray() + { + //TODO this could be improved, tricky bit is that writeTo is not trivial + // and has the side effect of compressing (meaning the writer.size() + // may be larger than necessary) + System.IO.MemoryStream out_Renamed = new System.IO.MemoryStream(writer.Length); + writeTo(out_Renamed); + return SupportClass.ToSByteArray(out_Renamed.ToArray()); + } + + public override void scriptLimits(ScriptLimits tag) + { + tagw.writeUI16(tag.scriptRecursionLimit); + tagw.writeUI16(tag.scriptTimeLimit); + encodeTag(tag); + } + } } \ No newline at end of file diff --git a/External/Extensions/AzothExtension/$(AppDir)/Tools/azoth/azoth.exe b/External/Extensions/AzothExtension/$(AppDir)/Tools/azoth/azoth.exe old mode 100644 new mode 100755 diff --git a/External/Extensions/LoomExtension/$(BaseDir)/Plugins/LoomContext.dll b/External/Extensions/LoomExtension/$(BaseDir)/Plugins/LoomContext.dll old mode 100644 new mode 100755 diff --git a/External/Extensions/Unity3DExtension/$(BaseDir)/Plugins/UnityContext.dll b/External/Extensions/Unity3DExtension/$(BaseDir)/Plugins/UnityContext.dll old mode 100644 new mode 100755 diff --git a/External/Plugins/AS2Context/AS2Context.csproj b/External/Plugins/AS2Context/AS2Context.csproj index df5c8d5571..f057d414b4 100644 --- a/External/Plugins/AS2Context/AS2Context.csproj +++ b/External/Plugins/AS2Context/AS2Context.csproj @@ -1,119 +1,85 @@  - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {74AD0487-CEF9-43FE-9283-BC6F79539ADE} - Library - Properties - AS2Context - AS2Context - - - - - 3.5 - - - v4.0 - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - DEBUG;TRACE - prompt - 4 - - - none - true - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - prompt - 4 - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - true - - - - - - - - - - - - {61885F70-B4DC-4B44-852D-5D6D03F2A734} - PluginCore - False - - - {4EBF2653-9654-4E40-880E-0046B3D6210E} - ASCompletion - False - - - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - + + + + Debug + AnyCPU + {74AD0487-CEF9-43FE-9283-BC6F79539ADE} + Library + Properties + AS2Context + AS2Context + net48 + true + false + false + false + x64;x86;AnyCPU + + + true + full + false + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + prompt + 4 + 9 + + + none + true + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + prompt + 4 + 9 + + + x86 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + 9 + + + x86 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + true + 9 + + + true + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + full + x64 + 9 + prompt + + + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + true + x64 + 9 + prompt + + + + + + + + + {61885F70-B4DC-4B44-852D-5D6D03F2A734} + PluginCore + False + + + {4EBF2653-9654-4E40-880E-0046B3D6210E} + ASCompletion + False + + \ No newline at end of file diff --git a/External/Plugins/AS2Context/AS2Settings.cs b/External/Plugins/AS2Context/AS2Settings.cs index e3db509435..78739653e4 100644 --- a/External/Plugins/AS2Context/AS2Settings.cs +++ b/External/Plugins/AS2Context/AS2Settings.cs @@ -27,8 +27,8 @@ public class AS2Settings : IContextSettings [LocalizedCategory("ASCompletion.Category.Documentation"), LocalizedDescription("ASCompletion.Description.DocumentationCommandLine"), DefaultValue(DEFAULT_DOC_COMMAND)] public string DocumentationCommandLine { - get { return documentationCommandLine; } - set { documentationCommandLine = value; } + get => documentationCommandLine; + set => documentationCommandLine = value; } #endregion @@ -69,7 +69,7 @@ public string DocumentationCommandLine const bool DEFAULT_FIXPACKAGEAUTOMATICALLY = true; protected bool checkSyntaxOnSave = DEFAULT_CHECKSYNTAX; - private bool lazyClasspathExploration = DEFAULT_LAZYMODE; + bool lazyClasspathExploration = DEFAULT_LAZYMODE; protected bool completionListAllTypes = DEFAULT_LISTALL; protected bool completionShowQualifiedTypes = DEFAULT_QUALIFY; protected bool completionEnabled = DEFAULT_COMPLETIONENABLED; @@ -80,42 +80,30 @@ public string DocumentationCommandLine protected InstalledSDK[] installedSDKs = null; [Browsable(false)] - public string LanguageId - { - get { return "AS2"; } - } + public string LanguageId => "AS2"; [Browsable(false)] - public string DefaultExtension - { - get { return ".as"; } - } + public string DefaultExtension => ".as"; [Browsable(false)] - public string CheckSyntaxRunning - { - get { return TextHelper.GetString("Info.MTASCRunning"); } - } + public string CheckSyntaxRunning => TextHelper.GetString("Info.MTASCRunning"); [Browsable(false)] - public string CheckSyntaxDone - { - get { return TextHelper.GetString("Info.MTASCDone"); } - } + public string CheckSyntaxDone => TextHelper.GetString("Info.MTASCDone"); [DisplayName("Check Syntax On Save")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CheckSyntaxOnSave"), DefaultValue(DEFAULT_CHECKSYNTAX)] public bool CheckSyntaxOnSave { - get { return checkSyntaxOnSave; } - set { checkSyntaxOnSave = value; } + get => checkSyntaxOnSave; + set => checkSyntaxOnSave = value; } [DisplayName("User Classpath")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.UserClasspath")] public string[] UserClasspath { - get { return userClasspath; } + get => userClasspath; set { userClasspath = value; @@ -127,7 +115,7 @@ public string[] UserClasspath [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("AS2Context.Description.MtascPath")] public InstalledSDK[] InstalledSDKs { - get { return installedSDKs; } + get => installedSDKs; set { installedSDKs = value; @@ -137,9 +125,7 @@ public InstalledSDK[] InstalledSDKs public InstalledSDK GetDefaultSDK() { - if (installedSDKs == null || installedSDKs.Length == 0) - return InstalledSDK.INVALID_SDK; - + if (installedSDKs.IsNullOrEmpty()) return InstalledSDK.INVALID_SDK; foreach (InstalledSDK sdk in installedSDKs) if (sdk.IsValid) return sdk; return InstalledSDK.INVALID_SDK; @@ -149,16 +135,16 @@ public InstalledSDK GetDefaultSDK() [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CompletionEnabled"), DefaultValue(DEFAULT_COMPLETIONENABLED)] public bool CompletionEnabled { - get { return completionEnabled; } - set { completionEnabled = value; } + get => completionEnabled; + set => completionEnabled = value; } [DisplayName("Generate Imports")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.GenerateImports"), DefaultValue(DEFAULT_GENERATEIMPORTS)] public bool GenerateImports { - get { return generateImports; } - set { generateImports = value; } + get => generateImports; + set => generateImports = value; } ///

@@ -168,8 +154,8 @@ public bool GenerateImports [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CompletionListAllTypes"), DefaultValue(DEFAULT_LISTALL)] public bool CompletionListAllTypes { - get { return completionListAllTypes; } - set { completionListAllTypes = value; } + get => completionListAllTypes; + set => completionListAllTypes = value; } /// @@ -179,8 +165,8 @@ public bool CompletionListAllTypes [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CompletionShowQualifiedTypes"), DefaultValue(DEFAULT_QUALIFY)] public bool CompletionShowQualifiedTypes { - get { return completionShowQualifiedTypes; } - set { completionShowQualifiedTypes = value; } + get => completionShowQualifiedTypes; + set => completionShowQualifiedTypes = value; } /// @@ -190,24 +176,24 @@ public bool CompletionShowQualifiedTypes [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.LazyClasspathExploration"), DefaultValue(DEFAULT_LAZYMODE)] public bool LazyClasspathExploration { - get { return lazyClasspathExploration; } - set { lazyClasspathExploration = value; } + get => lazyClasspathExploration; + set => lazyClasspathExploration = value; } [DisplayName("Play After Build")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.PlayAfterBuild"), DefaultValue(DEFAULT_PLAY)] public bool PlayAfterBuild { - get { return playAfterBuild; } - set { playAfterBuild = value; } + get => playAfterBuild; + set => playAfterBuild = value; } [DisplayName("Fix Package Automatically")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.FixPackageAutomatically"), DefaultValue(DEFAULT_FIXPACKAGEAUTOMATICALLY)] public bool FixPackageAutomatically { - get { return fixPackageAutomatically; } - set { fixPackageAutomatically = value; } + get => fixPackageAutomatically; + set => fixPackageAutomatically = value; } #endregion @@ -218,16 +204,16 @@ public bool FixPackageAutomatically const int DEFAULT_FLASHVERSION = 9; // Flash CS3 has a specific FP9 support for AS2 const string DEFAULT_MTASCCHECKPARAMS = "-mx -wimp"; - private int flashVersion = 9; - private string mmClassPath; - private bool useMtascIntrinsic = DEFAULT_USEMTASC; - private string mtascCheckParameters = DEFAULT_MTASCCHECKPARAMS; + int flashVersion = 9; + string mmClassPath; + bool useMtascIntrinsic = DEFAULT_USEMTASC; + string mtascCheckParameters = DEFAULT_MTASCCHECKPARAMS; [DisplayName("Use MTASC Intrinsics")] [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("AS2Context.Description.UseMtascIntrinsic"), DefaultValue(DEFAULT_USEMTASC)] public bool UseMtascIntrinsic { - get { return useMtascIntrinsic; } + get => useMtascIntrinsic; set { useMtascIntrinsic = value; @@ -239,8 +225,8 @@ public bool UseMtascIntrinsic [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("AS2Context.Description.MtascCheckParameters"), DefaultValue(DEFAULT_MTASCCHECKPARAMS)] public string MtascCheckParameters { - get { return mtascCheckParameters; } - set { mtascCheckParameters = value; } + get => mtascCheckParameters; + set => mtascCheckParameters = value; } [DisplayName("Flash IDE Classpath")] @@ -248,7 +234,7 @@ public string MtascCheckParameters [Editor(typeof(VistaFolderNameEditor), typeof(UITypeEditor))] public string MMClassPath { - get { return mmClassPath; } + get => mmClassPath; set { if (value == mmClassPath) return; mmClassPath = value; @@ -260,7 +246,7 @@ public string MMClassPath [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("AS2Context.Description.DefaultFlashVersion"), DefaultValue(DEFAULT_FLASHVERSION)] public int DefaultFlashVersion { - get { return flashVersion; } + get => flashVersion; set { if (value == flashVersion) return; if (value >= 6 && value <= 9) @@ -274,9 +260,9 @@ public int DefaultFlashVersion #endregion [Browsable(false)] - private void FireChanged() - { - if (OnClasspathChanged != null) OnClasspathChanged(); - } + void FireChanged() => OnClasspathChanged?.Invoke(); + + [Browsable(false)] + public string AddSpaceAfter { get; set; } } } diff --git a/External/Plugins/AS2Context/Context.cs b/External/Plugins/AS2Context/Context.cs index 1f28255dd8..16782d10c2 100644 --- a/External/Plugins/AS2Context/Context.cs +++ b/External/Plugins/AS2Context/Context.cs @@ -20,17 +20,17 @@ namespace AS2Context public class Context: ASContext { #region regular_expressions_definitions - static readonly protected Regex re_CMD_BuildCommand = + protected static readonly Regex re_CMD_BuildCommand = new Regex("@mtasc[\\s]+(?.*)", RegexOptions.Compiled | RegexOptions.Multiline); - static readonly protected Regex re_SplitParams = + protected static readonly Regex re_SplitParams = new Regex("[\\s](?\\-[A-z]+)", RegexOptions.Compiled | RegexOptions.Singleline); - static protected readonly Regex re_level = + protected static readonly Regex re_level = new Regex("^_level[0-9]+$", RegexOptions.Compiled | RegexOptions.Singleline); - static protected readonly Regex re_token = + protected static readonly Regex re_token = new Regex("^[a-z$_][a-z0-9$_]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled); - static protected readonly Regex re_package = + protected static readonly Regex re_package = new Regex("^[a-z$_][a-z0-9$_.]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled); - static protected readonly Regex re_lastDot = + protected static readonly Regex re_lastDot = new Regex("\\.[^<]", RegexOptions.RightToLeft | RegexOptions.Compiled); #endregion @@ -39,12 +39,12 @@ public class Context: ASContext protected bool hasLevels = true; protected string docType; - private AS2Settings as2settings; + readonly AS2Settings as2settings; public override IContextSettings Settings { - get { return settings; } - set { settings = value; } + get => settings; + set => settings = value; } /// @@ -94,6 +94,10 @@ public Context(AS2Settings initSettings) features.methodModifierDefault = Visibility.Public; // keywords + features.ClassKey = "class"; + features.InterfaceKey = "interface"; + features.ExtendsKey = "extends"; + features.ImplementsKey = "implements"; features.dot = "."; features.voidKey = "Void"; features.objectKey = "Object"; @@ -103,15 +107,6 @@ public Context(AS2Settings initSettings) features.arrayKey = "Array"; features.dynamicKey = "*"; features.importKey = "import"; - features.typesPreKeys = new string[] { "import", "new", "instanceof", "extends", "implements" }; - features.codeKeywords = new string[] { - "var", "function", "new", "delete", "instanceof", "return", "break", "continue", - "if", "else", "for", "in", "while", "do", "switch", "case", "default", "with", - "null", "undefined", "true", "false", "try", "catch", "finally", "throw" - }; - features.accessKeywords = new string[] { "override", "public", "private", "intrinsic", "static" }; - features.declKeywords = new string[] { "var", "function" }; - features.typesKeywords = new string[] { "import", "class", "interface" }; features.varKey = "var"; features.functionKey = "function"; features.getKey = "get"; @@ -121,7 +116,16 @@ public Context(AS2Settings initSettings) features.publicKey = "public"; features.privateKey = "private"; features.intrinsicKey = "intrinsic"; - + features.ReturnKey = "return"; + features.typesPreKeys = new[] { "import", "new", "instanceof", "extends", "implements" }; + features.codeKeywords = new[] { + "var", "function", "new", "delete", "instanceof", "return", "break", "continue", + "if", "else", "for", "in", "while", "do", "switch", "case", "default", "with", + "null", "undefined", "true", "false", "try", "catch", "finally", "throw" + }; + features.accessKeywords = new[] { "override", "public", "private", "intrinsic", "static" }; + features.declKeywords = new[] { "var", "function" }; + features.typesKeywords = new[] { "import", "class", "interface" }; features.functionArguments = new MemberModel("arguments", "FunctionArguments", FlagType.Variable | FlagType.LocalVar, 0); features.ArithmeticOperators = new HashSet { '+', '-', '*', '/' }; features.IncrementDecrementOperators = new[] {"++", "--"}; @@ -134,20 +138,19 @@ public Context(AS2Settings initSettings) #region classpath management /// - /// Classpathes & classes cache initialisation + /// Classpathes & classes cache initialization /// public override void BuildClassPath() { ReleaseClasspath(); started = true; - if (as2settings == null) throw new Exception("BuildClassPath() must be overridden"); - if (contextSetup == null) + if (as2settings is null) throw new Exception("BuildClassPath() must be overridden"); + contextSetup ??= new ContextSetupInfos { - contextSetup = new ContextSetupInfos(); - contextSetup.Lang = settings.LanguageId; - contextSetup.Platform = "Flash Player"; - contextSetup.Version = as2settings.DefaultFlashVersion + ".0"; - } + Lang = settings.LanguageId, + Platform = "Flash Player", + Version = as2settings.DefaultFlashVersion + ".0" + }; // external version definition platform = contextSetup.Platform; @@ -161,14 +164,13 @@ public override void BuildClassPath() classPath = new List(); // MTASC - string mtascPath = PluginBase.CurrentProject != null + var mtascPath = PluginBase.CurrentProject != null ? PluginBase.CurrentProject.CurrentSDK : PathHelper.ResolvePath(as2settings.GetDefaultSDK().Path); if (Path.GetExtension(mtascPath) != "") mtascPath = Path.GetDirectoryName(mtascPath); string path; - if ((as2settings.UseMtascIntrinsic || String.IsNullOrEmpty(as2settings.MMClassPath)) - && !String.IsNullOrEmpty(mtascPath) && Directory.Exists(mtascPath)) + if ((as2settings.UseMtascIntrinsic || string.IsNullOrEmpty(as2settings.MMClassPath)) && Directory.Exists(mtascPath)) { try { @@ -189,7 +191,7 @@ public override void BuildClassPath() catch {} } // Macromedia/Adobe - if (!String.IsNullOrEmpty(as2settings.MMClassPath) && Directory.Exists(as2settings.MMClassPath)) + if (Directory.Exists(as2settings.MMClassPath)) { if (classPath.Count == 0) { @@ -207,30 +209,30 @@ public override void BuildClassPath() if (Directory.Exists(path)) { PathModel aPath = new PathModel(path, this); - ManualExploration(aPath, new string[] { "aso", "FP7", "FP8", "FP9" }); + ManualExploration(aPath, new[] { "aso", "FP7", "FP8", "FP9" }); AddPath(aPath); } } } // add external pathes - List initCP = classPath; + var initCP = classPath; classPath = new List(); if (contextSetup.Classpath != null) { - foreach (string cpath in contextSetup.Classpath) + foreach (var cpath in contextSetup.Classpath) AddPath(cpath.Trim()); } // add library AddPath(Path.Combine(PathHelper.LibraryDir, "AS2/classes")); // add user pathes from settings - if (settings.UserClasspath != null && settings.UserClasspath.Length > 0) + if (!settings.UserClasspath.IsNullOrEmpty()) { - foreach(string cpath in settings.UserClasspath) AddPath(cpath.Trim()); + foreach(var cpath in settings.UserClasspath) AddPath(cpath.Trim()); } // add initial pathes - foreach(PathModel mpath in initCP) AddPath(mpath); + foreach(var mpath in initCP) AddPath(mpath); // parse top-level elements InitTopLevelElements(); @@ -251,14 +253,13 @@ public override void BuildClassPath() /// public override void RemoveClassCompilerCache() { - if (as2settings == null) return; + if (as2settings is null) return; - ClassModel pClass = cFile.GetPublicClass(); - if (as2settings.MMClassPath == null || pClass.IsVoid()) - return; - string package = (cFile.Package.Length > 0) ? cFile.Package + "." : ""; - string packagePath = dirSeparator + package.Replace('.', dirSeparatorChar); - string file = Path.Combine(as2settings.MMClassPath, "aso") + packagePath + package + pClass.Name + ".aso"; + var pClass = cFile.GetPublicClass(); + if (as2settings.MMClassPath is null || pClass.IsVoid()) return; + var package = (cFile.Package.Length > 0) ? cFile.Package + "." : ""; + var packagePath = dirSeparator + package.Replace('.', dirSeparatorChar); + var file = Path.Combine(as2settings.MMClassPath, "aso") + packagePath + package + pClass.Name + ".aso"; try { if (File.Exists(file)) File.Delete(file); @@ -273,11 +274,8 @@ public override ClassModel CurrentClass { get { - if (cFile == FileModel.Ignore) - { - return ClassModel.VoidClass; - } - if (cClass == null) + if (cFile == FileModel.Ignore) return ClassModel.VoidClass; + if (cClass is null) { cClass = ClassModel.VoidClass; cFile.OutOfDate = true; @@ -285,10 +283,7 @@ public override ClassModel CurrentClass // update class if (cFile.OutOfDate) { - if (cFile.FileName.Length > 0) - { - UpdateCurrentFile(true); - } + if (cFile.FileName.Length > 0) UpdateCurrentFile(true); // update "this" and "super" special vars UpdateTopLevelElements(); } @@ -305,14 +300,13 @@ public override ClassModel CurrentClass /// Completion visibility public override Visibility TypesAffinity(ClassModel inClass, ClassModel withClass) { - if (inClass == null || withClass == null) return Visibility.Public; + if (inClass is null || withClass is null) return Visibility.Public; // inheritance affinity - ClassModel tmp = inClass; - while (!tmp.IsVoid()) + var type = inClass; + while (!type.IsVoid()) { - if (tmp.Type == withClass.Type) - return Visibility.Public | Visibility.Private; - tmp = tmp.Extends; + if (type.Type == withClass.Type) return Visibility.Public | Visibility.Private; + type = type.Extends; } // public only return Visibility.Public; @@ -326,8 +320,9 @@ public override Visibility TypesAffinity(ClassModel inClass, ClassModel withClas /// Inherited type public override string DefaultInheritance(string package, string classname) { - if (package.Length == 0 && classname == features.objectKey) return features.voidKey; - else return features.objectKey; + return package.Length == 0 && classname == features.objectKey + ? features.voidKey + : features.objectKey; } /// @@ -337,51 +332,47 @@ public override string DefaultInheritance(string package, string classname) /// Response structure public override void ResolveTopLevelElement(string token, ASResult result) { - if (topLevel != null && topLevel.Members.Count > 0) + if (topLevel is null || topLevel.Members.Count == 0) return; + // current class + var inClass = Context.CurrentClass; + if (token == "this") { - // current class - ClassModel inClass = Context.CurrentClass; - if (token == "this") + result.Member = topLevel.Members.Search("this"); + if (inClass.IsVoid()) inClass = Context.ResolveType(result.Member.Type, null); + result.Type = inClass; + result.InFile = Context.CurrentModel; + result.RelClass = Context.CurrentClass; + return; + } + if (token == "super") + { + if (inClass.IsVoid()) { - result.Member = topLevel.Members.Search("this", 0, 0); - if (inClass.IsVoid()) - inClass = Context.ResolveType(result.Member.Type, null); - result.Type = inClass; - result.InFile = Context.CurrentModel; - return; + var thisMember = topLevel.Members.Search("this"); + inClass = Context.ResolveType(thisMember.Type, null); } - else if (token == "super") + inClass.ResolveExtends(); + var extends = inClass.Extends; + if (!extends.IsVoid()) { - if (inClass.IsVoid()) - { - MemberModel thisMember = topLevel.Members.Search("this", 0, 0); - inClass = Context.ResolveType(thisMember.Type, null); - } - inClass.ResolveExtends(); - ClassModel extends = inClass.Extends; - if (!extends.IsVoid()) - { - result.Member = topLevel.Members.Search("super", 0, 0); - result.Type = extends; - result.InFile = extends.InFile; - return; - } + result.Member = topLevel.Members.Search("super"); + result.Type = extends; + result.InFile = extends.InFile; + result.RelClass = Context.CurrentClass; + return; } + } - // other top-level elements - ASComplete.FindMember(token, topLevel, result, 0, 0); - if (!result.IsNull()) return; + // other top-level elements + ASComplete.FindMember(token, topLevel, result, 0, 0); + if (!result.IsNull()) return; - // special _levelN - if (hasLevels && token.StartsWith('_') && re_level.IsMatch(token)) - { - result.Member = new MemberModel(); - result.Member.Name = token; - result.Member.Flags = FlagType.Variable; - result.Member.Type = "MovieClip"; - result.Type = ResolveType("MovieClip", null); - result.InFile = topLevel; - } + // special _levelN + if (hasLevels && token.StartsWith('_') && re_level.IsMatch(token)) + { + result.Member = new MemberModel {Name = token, Flags = FlagType.Variable, Type = "MovieClip"}; + result.Type = ResolveType("MovieClip", null); + result.InFile = topLevel; } } @@ -392,15 +383,13 @@ public override void ResolveTopLevelElement(string token, ASResult result) /// Current file public override MemberList ResolveImports(FileModel inFile) { - if (inFile == cFile && completionCache.Imports != null) - return completionCache.Imports; - - MemberList imports = new MemberList(); - if (inFile == null) return imports; + if (inFile == cFile && completionCache.Imports != null) return completionCache.Imports; + var imports = new MemberList(); + if (inFile is null) return imports; bool filterImports = (inFile == cFile) && inFile.Classes.Count > 1; int lineMin = (filterImports && inPrivateSection) ? inFile.PrivateSectionIndex : 0; int lineMax = (filterImports && inPrivateSection) ? int.MaxValue : inFile.PrivateSectionIndex; - foreach (MemberModel item in inFile.Imports) + foreach (var item in inFile.Imports) { if (filterImports && (item.LineFrom < lineMin || item.LineFrom > lineMax)) continue; if (item.Name != "*") @@ -408,18 +397,18 @@ public override MemberList ResolveImports(FileModel inFile) if (settings.LazyClasspathExploration) imports.Add(item); else { - ClassModel type = ResolveType(item.Type, null); + var type = ResolveType(item.Type, null); if (!type.IsVoid()) imports.Add(type); else { // package-level declarations - int p = item.Type.LastIndexOf('.'); - if (p < 0) continue; - string package = item.Type.Substring(0, p); - string token = item.Type.Substring(p+1); - FileModel pack = ResolvePackage(package, false); - if (pack == null) continue; - MemberModel member = pack.Members.Search(token, 0, 0); + var p = item.Type.LastIndexOf('.'); + if (p == -1) continue; + var package = item.Type.Substring(0, p); + var token = item.Type.Substring(p+1); + var pack = ResolvePackage(package, false); + if (pack is null) continue; + var member = pack.Members.Search(token); if (member != null) imports.Add(member); } } @@ -427,14 +416,11 @@ public override MemberList ResolveImports(FileModel inFile) else { // classes matching wildcard - FileModel matches = ResolvePackage(item.Type.Substring(0, item.Type.Length - 2), false); - + var matches = ResolvePackage(item.Type.Substring(0, item.Type.Length - 2), false); if (matches != null) { - foreach (MemberModel import in matches.Imports) - imports.Add(import); - foreach (MemberModel member in matches.Members) - imports.Add(member); + imports.Add(matches.Imports); + imports.Add(matches.Members); } } } @@ -452,20 +438,16 @@ public override MemberList ResolveImports(FileModel inFile) public override bool IsImported(MemberModel member, int atLine) { if (member == ClassModel.VoidClass) return false; - FileModel cFile = Context.CurrentModel; - string fullName = member.Type; - string name = member.Name; - int lineMin = (Context.InPrivateSection) ? cFile.PrivateSectionIndex : 0; - int lineMax = atLine; + var cFile = Context.CurrentModel; + var fullName = member.Type; + var name = member.Name; + var lineMin = (Context.InPrivateSection) ? cFile.PrivateSectionIndex : 0; + var lineMax = atLine; foreach (MemberModel import in cFile.Imports) { - if (import.LineFrom >= lineMin && import.LineFrom <= lineMax && import.Name == name) - { - if (import.Type != fullName) throw new Exception("Ambiguous Type"); - return true; - } - else if (import.Name == "*" && import.Type.Replace("*", name) == fullName) + if (import.LineFrom >= lineMin && import.LineFrom <= lineMax && import.Name == name && import.Type == fullName) return true; + if (import.Name == "*" && import.Type.Replace("*", name) == fullName) return true; } return false; } @@ -479,15 +461,14 @@ public override bool IsImported(MemberModel member, int atLine) public override ClassModel ResolveType(string cname, FileModel inFile) { // unknown type - if (string.IsNullOrEmpty(cname) || cname == features.voidKey || classPath == null) + if (string.IsNullOrEmpty(cname) || cname == features.voidKey || classPath is null) return ClassModel.VoidClass; // typed array - if (cname.IndexOf('@') > 0) - return ResolveTypeIndex(cname, inFile); + if (cname.Contains('@')) return ResolveTypeIndex(cname, inFile); - string package = ""; - Match m = re_lastDot.Match(cname); + var package = ""; + var m = re_lastDot.Match(cname); if (m.Success) { package = cname.Substring(0, m.Index); @@ -498,7 +479,7 @@ public override ClassModel ResolveType(string cname, FileModel inFile) if (inFile != null && inFile.Classes.Count > 0) { foreach (ClassModel aClass in inFile.Classes) - if (aClass.Name == cname && (package == "" || package == inFile.Package)) + if (aClass.Name == cname && (package.Length == 0 || package == inFile.Package)) return aClass; } @@ -506,7 +487,7 @@ public override ClassModel ResolveType(string cname, FileModel inFile) string inPackage = (features.hasPackages && inFile != null) ? inFile.Package : ""; // search in imported classes - if (package == "" && inFile != null) + if (package.Length == 0 && inFile != null) { foreach (MemberModel import in inFile.Imports) { @@ -516,22 +497,22 @@ public override ClassModel ResolveType(string cname, FileModel inFile) package = import.Type.Substring(0, import.Type.Length - cname.Length - 1); break; } - else if (features.hasImportsWildcard) + if (features.hasImportsWildcard) { if (import.Name == "*" && import.Type.Length > 2) { // try wildcards - string testPackage = import.Type.Substring(0, import.Type.Length - 2); + var testPackage = import.Type.Substring(0, import.Type.Length - 2); if (settings.LazyClasspathExploration) { - ClassModel testClass = GetModel(testPackage, cname, inPackage); + var testClass = GetModel(testPackage, cname, inPackage); if (!testClass.IsVoid()) return testClass; } else { - FileModel pack = ResolvePackage(testPackage, false); - if (pack == null) continue; - MemberModel found = pack.Imports.Search(cname, 0, 0); + var pack = ResolvePackage(testPackage, false); + if (pack is null) continue; + var found = pack.Imports.Search(cname); if (found != null) return ResolveType(found.Type, null); } } @@ -540,14 +521,14 @@ public override ClassModel ResolveType(string cname, FileModel inFile) { if (settings.LazyClasspathExploration) { - ClassModel testClass = GetModel(import.Type, cname, inPackage); + var testClass = GetModel(import.Type, cname, inPackage); if (!testClass.IsVoid()) return testClass; } else { - FileModel pack = ResolvePackage(import.Type, false); - if (pack == null) continue; - MemberModel found = pack.Imports.Search(cname, 0, 0); + var pack = ResolvePackage(import.Type, false); + if (pack is null) continue; + var found = pack.Imports.Search(cname); if (found != null) return ResolveType(found.Type, null); } } @@ -560,15 +541,25 @@ public override ClassModel ResolveType(string cname, FileModel inFile) public override ClassModel ResolveToken(string token, FileModel inFile) { - if (token?.Length > 0) + var tokenLength = token?.Length ?? 0; + if (tokenLength > 0) { if (token == "true" || token == "false") return ResolveType(features.booleanKey, inFile); - if (char.IsDigit(token, 0) || (token.Length > 1 && token[0] == '-' && char.IsDigit(token, 1))) return ResolveType(features.numberKey, inFile); var first = token[0]; - var last = token[token.Length - 1]; + if (char.IsDigit(token, 0) + // for example: -1, +1 + || (tokenLength > 1 && (first == '-' || first == '+') && char.IsDigit(token, 1)) + // for example: --1, ++1 + || (tokenLength > 2 && ((first == '-' && token[1] == '-') || (first == '+' && token[1] == '+')) && char.IsDigit(token, 2))) + { + if (features.IntegerKey is null) return ResolveType(features.numberKey, inFile); + if (token.Contains('.') || token.Contains('e')) return ResolveType(features.numberKey, inFile); + return ResolveType(features.IntegerKey, inFile); + } + var last = token[tokenLength - 1]; if (first == '{' && last == '}') return ResolveType(features.objectKey, inFile); if (first == '[' && last == ']') return ResolveType(features.arrayKey, inFile); - if (first == '"' || first == '\'') return ResolveType(features.stringKey, inFile); + if (tokenLength > 1 && (first == '"' || first == '\'') && last == first) return ResolveType(features.stringKey, inFile); } return base.ResolveToken(token, inFile); } @@ -576,7 +567,7 @@ public override ClassModel ResolveToken(string token, FileModel inFile) protected ClassModel ResolveTypeIndex(string cname, FileModel inFile) { int p = cname.IndexOf('@'); - if (p < 0) return ClassModel.VoidClass; + if (p == -1) return ClassModel.VoidClass; string indexType = cname.Substring(p + 1); string baseType = cname.Substring(0, p); @@ -588,20 +579,20 @@ protected ClassModel ResolveTypeIndex(string cname, FileModel inFile) if (baseType == inFile.Context.Features.dynamicKey) { - if (!indexClass.IsVoid()) return indexClass; - return MakeCustomObjectClass(originalClass, indexType); + return !indexClass.IsVoid() + ? indexClass + : MakeCustomObjectClass(originalClass, indexType); } if (indexClass.IsVoid()) return originalClass; indexType = indexClass.QualifiedName; - FileModel aFile = originalClass.InFile; + var aFile = originalClass.InFile; // is the type already cloned? - foreach (ClassModel otherClass in aFile.Classes) + foreach (var otherClass in aFile.Classes) if (otherClass.IndexType == indexType) return otherClass; // clone the type - ClassModel aClass = originalClass.Clone() as ClassModel; - + var aClass = originalClass.Clone(); aClass.Name = baseType + "@" + indexType; aClass.IndexType = indexType; @@ -613,19 +604,18 @@ protected ClassModel ResolveTypeIndex(string cname, FileModel inFile) } // replace 'Object' and '*' by the index type else - foreach (MemberModel member in aClass.Members) - { - if (member.Type == features.objectKey || member.Type == "*") member.Type = indexType; - if (member.Parameters != null) + foreach (var member in aClass.Members) { - foreach (MemberModel param in member.Parameters) + if (member.Type == features.objectKey || member.Type == "*") member.Type = indexType; + if (member.Parameters != null) { - if (param.Name == "value" - && (param.Type == features.objectKey || param.Type == "*")) - param.Type = indexType; + foreach (var param in member.Parameters) + { + if (param.Name == "value" && (param.Type == features.objectKey || param.Type == "*")) + param.Type = indexType; + } } } - } aFile.Classes.Add(aClass); return aClass; @@ -633,21 +623,24 @@ protected ClassModel ResolveTypeIndex(string cname, FileModel inFile) protected ClassModel MakeCustomObjectClass(ClassModel objectClass, string indexType) { - foreach (ClassModel c in objectClass.InFile.Classes) - if (c.IndexType == indexType) return c; - - ClassModel aClass = new ClassModel(); - aClass.Flags = objectClass.Flags; - aClass.Access = objectClass.Access; - aClass.ExtendsType = ""; - aClass.Name = objectClass.QualifiedName + "@" + indexType; - aClass.IndexType = indexType; - aClass.InFile = objectClass.InFile; + foreach (var c in objectClass.InFile.Classes) + if (c.IndexType == indexType) + return c; - FlagType flags = FlagType.Dynamic | FlagType.Variable | FlagType.AutomaticVar; - foreach (string prop in indexType.Split(',')) + var aClass = new ClassModel { - MemberModel member = new MemberModel(prop, "", flags, Visibility.Public); + Flags = objectClass.Flags, + Access = objectClass.Access, + ExtendsType = "", + Name = objectClass.QualifiedName + "@" + indexType, + IndexType = indexType, + InFile = objectClass.InFile + }; + + const FlagType flags = FlagType.Dynamic | FlagType.Variable | FlagType.AutomaticVar; + foreach (var prop in indexType.Split(',')) + { + var member = new MemberModel(prop, "", flags, Visibility.Public); aClass.Members.Add(member); } objectClass.InFile.Classes.Add(aClass); @@ -661,16 +654,16 @@ protected ClassModel MakeCustomObjectClass(ClassModel objectClass, string indexT /// Class name /// Package reference for resolution /// - public override ClassModel GetModel(string package, string cname, string inPackage) + public override ClassModel GetModel(string package, string cname, string? inPackage) { if (!settings.LazyClasspathExploration) { bool testSamePackage = package.Length == 0 && features.hasPackages; bool testModule = package.Length > 0 && features.hasModules; - foreach (PathModel aPath in classPath) + foreach (var aPath in classPath) if (aPath.IsValid && !aPath.Updating) { - ClassModel found = LookupClass(package, cname, inPackage, testSamePackage, testModule, aPath); + var found = LookupClass(package, cname, inPackage, testSamePackage, testModule, aPath); if (found != null) return found; } if (classPath.Count > 0 && classPath[0].IsTemporaryPath) @@ -686,8 +679,7 @@ public override ClassModel GetModel(string package, string cname, string inPacka model = LocateClassFile(classPath[0], fileName); } catch { } - if (model != null) return model; - else return ClassModel.VoidClass; + return model ?? ClassModel.VoidClass; } } else @@ -698,82 +690,76 @@ public override ClassModel GetModel(string package, string cname, string inPacka foreach (PathModel aPath in classPath) if (aPath.IsValid && !aPath.Updating) { - ClassModel model = LocateClassFile(aPath, fileName); + var model = LocateClassFile(aPath, fileName); if (model != null) return model; } } return ClassModel.VoidClass; } - private ClassModel LookupClass(string package, string cname, string inPackage, bool testSamePackage, bool testModule, PathModel aPath) + ClassModel LookupClass(string package, string cname, string? inPackage, bool testSamePackage, bool testModule, PathModel aPath) { - bool matchParentPackage = testSamePackage && features.hasFriendlyParentPackages; - - ClassModel found = null; - int pLen = inPackage.Length; - - aPath.ForeachFile((aFile) => + ClassModel result = null; + inPackage ??= string.Empty; + var matchParentPackage = testSamePackage && features.hasFriendlyParentPackages; + var pLen = inPackage.Length; + aPath.ForeachFile(aFile => { - string pkg = aFile.Package; + var count = aFile.Classes.Count; + if (count == 0) return true; + var pkg = aFile.Package; // qualified path - if (pkg == package && aFile.Classes.Count > 0) + if (pkg == package) { - var count = aFile.Classes.Count; for (var i = 0; i < count; i++) { var aClass = aFile.Classes[i]; if (aClass.Name == cname && (pkg == "" || aFile.Module == "" || aFile.Module == aClass.Name)) { - found = aClass; + result = aClass; return false; } } } - else if (testModule && aFile.FullPackage == package && aFile.Classes.Count > 0) + else if (testModule && aFile.FullPackage == package) { - var count = aFile.Classes.Count; for (var i = 0; i < count; i++) { var aClass = aFile.Classes[i]; if (aClass.Name == cname) { - found = aClass; + result = aClass; return false; } } } // in the same (or parent) package - else if (testSamePackage) + else if (testSamePackage && (pkg == inPackage || (matchParentPackage && pkg.Length < pLen && inPackage.StartsWithOrdinal(pkg + ".")))) { - if (inPackage == pkg || (matchParentPackage && pkg.Length < pLen && inPackage.StartsWithOrdinal(pkg + "."))) + for (var i = 0; i < count; i++) { - var count = aFile.Classes.Count; - for (var i = 0; i < count; i++) + var aClass = aFile.Classes[i]; + if (aClass.Name == cname) { - var aClass = aFile.Classes[i]; - if (aClass.Name == cname /*&& (aFile.Module == "" || aFile.Module == aClass.Name)*/) - { - found = aClass; - return false; - } + result = aClass; + return false; } } } return true; }); - return found; + return result; } - private ClassModel LocateClassFile(PathModel aPath, string fileName) + ClassModel LocateClassFile(PathModel aPath, string fileName) { if (!aPath.IsValid) return null; try { string path = Path.Combine(aPath.Path, fileName); // cached file - if (aPath.HasFile(path)) + if (aPath.TryGetFile(path, out var nFile)) { - FileModel nFile = aPath.GetFile(path); if (nFile.Context != this) { // not associated with this context -> refresh @@ -783,9 +769,9 @@ private ClassModel LocateClassFile(PathModel aPath, string fileName) return nFile.GetPublicClass(); } // non-cached existing file - else if (File.Exists(path)) + if (File.Exists(path)) { - FileModel nFile = GetFileModel(path); + nFile = GetFileModel(path); if (nFile != null) { aPath.AddFile(nFile); @@ -813,110 +799,104 @@ public override void CheckModel(bool onFileOpen) base.CheckModel(onFileOpen); return; } - string prevPackage = (onFileOpen) ? null : cFile.Package; - string prevCname = (onFileOpen) ? null : cFile.GetPublicClass().Name; + string prevPackage = null; + string prevCname = null; + if(onFileOpen) + { + prevPackage = cFile.Package; + prevCname = cFile.GetPublicClass().Name; + } // refresh model base.CheckModel(onFileOpen); if (!MessageBar.Locked && features.checkFileName && cFile.Version > 1) { - string package = cFile.Package; - ClassModel pClass = cFile.GetPublicClass(); - if (package.Length > 0) + var package = cFile.Package; + var pClass = cFile.GetPublicClass(); + var pathname = package.Replace('.', Path.DirectorySeparatorChar); + var fullpath = Path.GetDirectoryName(cFile.FileName); + if (package.Length == 0 || !fullpath.EndsWithOrdinal(pathname)) { - string pathname = package.Replace('.', Path.DirectorySeparatorChar); - string fullpath = Path.GetDirectoryName(cFile.FileName); - if (!fullpath.EndsWithOrdinal(pathname)) + if (settings.FixPackageAutomatically && PluginBase.MainForm.CurrentDocument?.SciControl is { } sci) { - if (settings.FixPackageAutomatically && CurSciControl != null) + var packagePattern = cFile.Context.Settings.LanguageId == "AS2" + ? new Regex("class\\s+(" + cFile.Package.Replace(".", "\\.") + "\\." + pClass.Name + ')') + : new Regex("package\\s+(" + cFile.Package.Replace(".", "\\.") + ')'); + + var regexPackageLine = ""; + var pos = -1; + var txt = ""; + var p = 0; + var counter = sci.Length; + while (p < counter) { - bool isAs2 = cFile.Context.Settings.LanguageId == "AS2"; - - int pos = -1; - - string txt = ""; - string regexPackageLine = ""; - - int counter = CurSciControl.Length; - int p = 0; - Regex packagePattern = null; - if (isAs2) - { - packagePattern = new Regex("class\\s+(" + cFile.Package.Replace(".", "\\.") + "\\." + pClass.Name + ')'); - } - else - { - packagePattern = new Regex("package\\s+(" + cFile.Package.Replace(".", "\\.") + ')'); - } - while (p < counter) + var c = (char) sci.CharAt(p++); + txt += c; + if (txt.Length > 5 && c <= 32) { - char c = (char)CurSciControl.CharAt(p++); - txt += c; - if (txt.Length > 5 && c <= 32) + var m = packagePattern.Match(txt); + if (m.Success) { - Match m = packagePattern.Match(txt); - if (m.Success) - { - pos = m.Groups[1].Index; - regexPackageLine = m.Value; - break; - } + pos = m.Groups[1].Index; + regexPackageLine = m.Value; + break; } } + } - if (regexPackageLine.Length > 0 && pos > -1) + if (regexPackageLine.Length > 0 && pos > -1) + { + var orgid = "Info.PackageDontMatchFilePath"; + var classpaths = Context.Classpath; + if (classpaths != null) { - string orgid = "Info.PackageDontMatchFilePath"; - List classpaths = Context.Classpath; - if (classpaths != null) + string correctPath = null; + foreach (var pm in classpaths) { - string correctPath = null; - foreach (PathModel pm in classpaths) + if (fullpath.Contains(pm.Path) && fullpath.Length > pm.Path.Length) { - if (fullpath.IndexOfOrdinal(pm.Path) > -1 && fullpath.Length > pm.Path.Length) - { - correctPath = fullpath.Substring(pm.Path.Length + 1); - } - else if (fullpath.ToLower() == pm.Path.ToLower()) - { - correctPath = ""; // We are in root, no package.. - } + correctPath = fullpath.Substring(pm.Path.Length + 1); } - if (correctPath != null) + else if (fullpath.ToLower() == pm.Path.ToLower()) { - correctPath = correctPath.Replace(Path.DirectorySeparatorChar, '.'); - CurSciControl.SetSel(pos, pos + cFile.Package.Length); - CurSciControl.ReplaceSel(correctPath); - orgid = "Info.PackageDidntMatchFilePath"; + correctPath = ""; // We are in root, no package.. } } - string org = TextHelper.GetString(orgid); - string msg = String.Format(org, package) + "\n" + cFile.FileName; - MessageBar.ShowWarning(msg); + if (correctPath == "" && package.Length == 0) return; + if (correctPath != null) + { + correctPath = correctPath.Replace(Path.DirectorySeparatorChar, '.'); + sci.SetSel(pos, pos + cFile.Package.Length); + sci.ReplaceSel(correctPath); + orgid = "Info.PackageDidntMatchFilePath"; + } } - - } - else - { - string org = TextHelper.GetString("Info.PackageDontMatchFilePath"); - string msg = String.Format(org, package) + "\n" + cFile.FileName; + var org = TextHelper.GetString(orgid); + var msg = string.Format(org, package) + "\n" + cFile.FileName; MessageBar.ShowWarning(msg); } - return; } - else MessageBar.HideWarning(); + else + { + var org = TextHelper.GetString("Info.PackageDontMatchFilePath"); + var msg = string.Format(org, package) + "\n" + cFile.FileName; + MessageBar.ShowWarning(msg); + } + return; } + + MessageBar.HideWarning(); if (!pClass.IsVoid()) { string cname = pClass.Name; if (prevPackage != package || prevCname != cname) { - if (package.Length > 0) cname = package + "." + cname; - string filename = cname.Replace('.', Path.DirectorySeparatorChar) + Path.GetExtension(cFile.FileName); + cname = package + "." + cname; + var filename = cname.Replace('.', Path.DirectorySeparatorChar) + Path.GetExtension(cFile.FileName); if (!cFile.FileName.ToUpper().EndsWithOrdinal(filename.ToUpper())) { string org = TextHelper.GetString("Info.TypeDontMatchFileName"); - string msg = String.Format(org, cname) + "\n" + cFile.FileName; + string msg = string.Format(org, cname) + "\n" + cFile.FileName; MessageBar.ShowWarning(msg); } else MessageBar.HideWarning(); @@ -925,24 +905,22 @@ public override void CheckModel(bool onFileOpen) } } - /// /// Update Flash intrinsic known vars /// protected override void UpdateTopLevelElements() { - MemberModel special; - special = topLevel.Members.Search("this", 0, 0); + var special = topLevel.Members.Search("this"); if (special != null) { if (!cClass.IsVoid()) special.Type = cClass.QualifiedName; else special.Type = (cFile.Version > 1) ? features.voidKey : docType; } - special = topLevel.Members.Search("super", 0, 0); + special = topLevel.Members.Search("super"); if (special != null) { cClass.ResolveExtends(); - ClassModel extends = cClass.Extends; + var extends = cClass.Extends; if (!extends.IsVoid()) special.Type = extends.QualifiedName; else special.Type = (cFile.Version > 1) ? features.voidKey : features.objectKey; } @@ -953,22 +931,25 @@ protected override void UpdateTopLevelElements() /// protected override void InitTopLevelElements() { - string filename = "toplevel.as"; + var filename = "toplevel.as"; topLevel = new FileModel(filename); // search top-level declaration - foreach(PathModel aPath in classPath) - if (File.Exists(Path.Combine(aPath.Path, filename))) + foreach (var aPath in classPath) { - filename = Path.Combine(aPath.Path, filename); - topLevel = GetCachedFileModel(filename); - break; + var path = Path.Combine(aPath.Path, filename); + if (File.Exists(path)) + { + filename = path; + topLevel = GetCachedFileModel(filename); + break; + } } if (File.Exists(filename)) { // MTASC toplevel-style declaration: - ClassModel tlClass = topLevel.GetPublicClass(); + var tlClass = topLevel.GetPublicClass(); if (!tlClass.IsVoid()) { topLevel.Members = tlClass.Members; @@ -977,23 +958,14 @@ protected override void InitTopLevelElements() } } // not found - else - { - //ErrorHandler.ShowInfo("Top-level elements class not found. Please check your Program Settings."); - } - if (topLevel.Members.Search("_root", 0, 0) == null) - topLevel.Members.Add(new MemberModel("_root", docType, FlagType.Variable, Visibility.Public)); - if (topLevel.Members.Search("_global", 0, 0) == null) - topLevel.Members.Add(new MemberModel("_global", features.objectKey, FlagType.Variable, Visibility.Public)); - if (topLevel.Members.Search("this", 0, 0) == null) - topLevel.Members.Add(new MemberModel("this", "", FlagType.Variable, Visibility.Public)); - if (topLevel.Members.Search("super", 0, 0) == null) - topLevel.Members.Add(new MemberModel("super", "", FlagType.Variable, Visibility.Public)); - if (topLevel.Members.Search(features.voidKey, 0, 0) == null) - topLevel.Members.Add(new MemberModel(features.voidKey, "", FlagType.Class | FlagType.Intrinsic, Visibility.Public)); + if (!topLevel.Members.Contains("_root")) topLevel.Members.Add(new MemberModel("_root", docType, FlagType.Variable, Visibility.Public)); + if (!topLevel.Members.Contains("_global")) topLevel.Members.Add(new MemberModel("_global", features.objectKey, FlagType.Variable, Visibility.Public)); + if (!topLevel.Members.Contains("this")) topLevel.Members.Add(new MemberModel("this", string.Empty, FlagType.Variable, Visibility.Public)); + if (!topLevel.Members.Contains("super")) topLevel.Members.Add(new MemberModel("super", string.Empty, FlagType.Variable, Visibility.Public)); + if (!topLevel.Members.Contains(features.voidKey)) topLevel.Members.Add(new MemberModel(features.voidKey, string.Empty, FlagType.Class | FlagType.Intrinsic, Visibility.Public)); topLevel.Members.Sort(); - foreach (MemberModel member in topLevel.Members) + foreach (var member in topLevel.Members) member.Flags |= FlagType.Intrinsic; } @@ -1005,76 +977,73 @@ protected override void InitTopLevelElements() /// Package folders and types public override FileModel ResolvePackage(string name, bool lazyMode) { - if (name == null) name = ""; + if (name is null) name = ""; else if (!re_package.IsMatch(name)) return null; - - FileModel pModel = new FileModel(); - pModel.Package = name; - pModel.OutOfDate = false; - - string packagePath = name.Replace('.', dirSeparatorChar); - foreach (PathModel aPath in classPath) if (aPath.IsValid && !aPath.Updating) - { - // explore file system - if (lazyMode || settings.LazyClasspathExploration || aPath.IsTemporaryPath) + var pModel = new FileModel {Package = name, OutOfDate = false}; + var packagePath = name.Replace('.', dirSeparatorChar); + foreach (PathModel aPath in classPath) + if (aPath.IsValid && !aPath.Updating) { - string path = Path.Combine(aPath.Path, packagePath); - if (Directory.Exists(path)) + // explore file system + if (lazyMode || settings.LazyClasspathExploration || aPath.IsTemporaryPath) { - try - { - PopulatePackageEntries(name, path, pModel.Imports); - PopulateClassesEntries(name, path, pModel.Imports); - } - catch (Exception ex) - { - ErrorManager.ShowError(ex); - } - } - } - // explore parsed models - else - { - string prevPackage = null; - string packagePrefix = name.Length > 0 ? name + "." : ""; - int nameLen = name.Length + 1; - aPath.ForeachFile((model) => - { - if (!model.HasPackage) - return true; // skip - string package = model.Package; - if (package == name) + var path = Path.Combine(aPath.Path, packagePath); + if (Directory.Exists(path)) { - var count = model.Classes.Count; - for (var i = 0; i < count; i++) + try { - var type = model.Classes[i]; - if (type.IndexType != null) continue; - if (type.Access != Visibility.Private) - pModel.Imports.Add(type.ToMemberModel()); + PopulatePackageEntries(name, path, pModel.Imports); + PopulateClassesEntries(name, path, pModel.Imports); } - count = model.Members.Count; - for (var i = 0; i < count; i++) + catch (Exception ex) { - pModel.Members.Add(model.Members[i].Clone() as MemberModel); + ErrorManager.ShowError(ex); } } - else if (package != prevPackage - && (package.Length > name.Length && package.StartsWithOrdinal(packagePrefix))) // imports + } + // explore parsed models + else + { + string prevPackage = null; + string packagePrefix = name.Length > 0 ? name + "." : ""; + int nameLen = name.Length + 1; + aPath.ForeachFile((model) => { - prevPackage = package; - if (nameLen > 1) package = package.Substring(nameLen); - int p = package.IndexOf('.'); - if (p > 0) package = package.Substring(0, p); - if (pModel.Imports.Search(package, 0, 0) == null) // sub packages + if (!model.HasPackage) + return true; // skip + string package = model.Package; + if (package == name) + { + var count = model.Classes.Count; + for (var i = 0; i < count; i++) + { + var type = model.Classes[i]; + if (type.IndexType != null) continue; + if (type.Access != Visibility.Private) + pModel.Imports.Add(type.ToMemberModel()); + } + count = model.Members.Count; + for (var i = 0; i < count; i++) + { + pModel.Members.Add(model.Members[i].Clone()); + } + } + else if (package != prevPackage + && (package.Length > name.Length && package.StartsWithOrdinal(packagePrefix))) // imports { - pModel.Imports.Add(new MemberModel(package, package, FlagType.Package, Visibility.Public)); + prevPackage = package; + if (nameLen > 1) package = package.Substring(nameLen); + int p = package.IndexOf('.'); + if (p > 0) package = package.Substring(0, p); + if (!pModel.Imports.Contains(package)) // sub packages + { + pModel.Imports.Add(new MemberModel(package, package, FlagType.Package, Visibility.Public)); + } } - } - return true; - }); + return true; + }); + } } - } // result if (pModel.Imports.Count > 0 || pModel.Members.Count > 0) @@ -1082,10 +1051,10 @@ public override FileModel ResolvePackage(string name, bool lazyMode) pModel.Imports.Sort(); return pModel; } - else return null; + return null; } - private void PopulateClassesEntries(string package, string path, MemberList memberList) + void PopulateClassesEntries(string package, string path, MemberList memberList) { string[] fileEntries = null; try @@ -1093,24 +1062,22 @@ private void PopulateClassesEntries(string package, string path, MemberList memb fileEntries = Directory.GetFiles(path, "*" + settings.DefaultExtension); } catch { } - if (fileEntries == null) return; - string mname; - string type; - FlagType flag = FlagType.Class | ((package == null) ? FlagType.Intrinsic : 0); + if (fileEntries is null) return; + var flag = FlagType.Class | (package is null ? FlagType.Intrinsic : 0); foreach (string entry in fileEntries) { - mname = GetLastStringToken(entry, dirSeparator); + var mname = GetLastStringToken(entry, dirSeparator); mname = mname.Substring(0, mname.LastIndexOf('.')); - if (mname.Length > 0 && memberList.Search(mname, 0, 0) == null && re_token.IsMatch(mname)) + if (mname.Length > 0 && !memberList.Contains(mname) && re_token.IsMatch(mname)) { - type = mname; + var type = mname; if (package.Length > 0) type = package + "." + mname; memberList.Add(new MemberModel(mname, type, flag, Visibility.Public)); } } } - private void PopulatePackageEntries(string package, string path, MemberList memberList) + static void PopulatePackageEntries(string package, string path, MemberList memberList) { string[] dirEntries = null; try @@ -1118,16 +1085,14 @@ private void PopulatePackageEntries(string package, string path, MemberList memb dirEntries = Directory.GetDirectories(path); } catch { } - if (dirEntries == null) return; + if (dirEntries is null) return; - string mname; - string type; foreach (string entry in dirEntries) { - mname = GetLastStringToken(entry, dirSeparator); - if (mname.Length > 0 && memberList.Search(mname, 0, 0) == null && re_token.IsMatch(mname)) + var mname = GetLastStringToken(entry, dirSeparator); + if (mname.Length > 0 && !memberList.Contains(mname) && re_token.IsMatch(mname)) { - type = mname; + var type = mname; if (package.Length > 0) type = package + "." + mname; memberList.Add(new MemberModel(mname, type, FlagType.Package, Visibility.Public)); } @@ -1140,12 +1105,9 @@ private void PopulatePackageEntries(string package, string path, MemberList memb /// public override MemberList GetTopLevelElements() { - if (topLevel != null) - { - if (topLevel.OutOfDate) InitTopLevelElements(); - return topLevel.Members; - } - else return new MemberList(); + if (topLevel is null) return new MemberList(); + if (topLevel.OutOfDate) InitTopLevelElements(); + return topLevel.Members; } /// @@ -1155,86 +1117,77 @@ public override MemberList GetTopLevelElements() public override MemberList GetVisibleExternalElements() { if (!IsFileValid) return new MemberList(); - - if (completionCache.IsDirty) + if (!completionCache.IsDirty) return completionCache.Elements; + var elements = new MemberList(); + // root types & packages + var baseElements = ResolvePackage(null, false); + if (baseElements != null) { - MemberList elements = new MemberList(); - // root types & packages - FileModel baseElements = ResolvePackage(null, false); - if (baseElements != null) - { - elements.Add(baseElements.Imports); - elements.Add(baseElements.Members); - } - elements.Add(new MemberModel(features.voidKey, features.voidKey, FlagType.Class | FlagType.Intrinsic, 0)); + elements.Add(baseElements.Imports); + elements.Add(baseElements.Members); + } + elements.Add(new MemberModel(features.voidKey, features.voidKey, FlagType.Class | FlagType.Intrinsic, 0)); - //bool qualify = Settings.CompletionShowQualifiedTypes && settings.GenerateImports; - - // other classes in same package - if (features.hasPackages && cFile.Package != "") + // other classes in same package + if (features.hasPackages && cFile.Package != "") + { + var packageElements = ResolvePackage(cFile.Package, false); + if (packageElements != null) { - FileModel packageElements = ResolvePackage(cFile.Package, false); - if (packageElements != null) + foreach (var member in packageElements.Imports) { - foreach (MemberModel member in packageElements.Imports) - { - if (member.Flags != FlagType.Package) - { - //if (qualify) member.Name = member.Type; - elements.Add(member); - } - } - foreach (MemberModel member in packageElements.Members) + if (member.Flags != FlagType.Package) { - string pkg = member.InFile.Package; - //if (qualify && pkg != "") member.Name = pkg + "." + member.Name; - member.Type = pkg != "" ? pkg + "." + member.Name : member.Name; elements.Add(member); } } + foreach (var member in packageElements.Members) + { + var pkg = member.InFile.Package; + member.Type = pkg != "" ? pkg + "." + member.Name : member.Name; + elements.Add(member); + } } - // other classes in same file - if (cFile.PrivateSectionIndex > 0) + } + // other classes in same file + if (cFile.PrivateSectionIndex > 0) + { + if (inPrivateSection && cFile.Classes.Count > 1) { - if (inPrivateSection && cFile.Classes.Count > 1) + var mainClass = cFile.GetPublicClass(); + if (!mainClass.IsVoid()) { - ClassModel mainClass = cFile.GetPublicClass(); - if (!mainClass.IsVoid()) - { - MemberModel toRemove = elements.Search(mainClass.Name, 0, 0); - if (toRemove != null && toRemove.Type == mainClass.QualifiedName) - elements.Remove(toRemove); - } + var toRemove = elements.Search(mainClass.Name); + if (toRemove != null && toRemove.Type == mainClass.QualifiedName) + elements.Remove(toRemove); } + } - MemberModel member; - foreach (ClassModel aClass in cFile.Classes) + foreach (var aClass in cFile.Classes) + { + if (features.hasMultipleDefs || aClass.Access == Visibility.Private) { - if (features.hasMultipleDefs || aClass.Access == Visibility.Private) - { - member = aClass.ToMemberModel(); - elements.Add(member); - } + elements.Add(aClass.ToMemberModel()); } } + } - // imports - elements.Add(ResolveImports(CurrentModel)); + // imports + elements.Add(ResolveImports(CurrentModel)); - // in cache - elements.Sort(); - completionCache = new CompletionCache(this, elements); + // in cache + elements.Sort(); + completionCache = new CompletionCache(this, elements); - // known classes colorization - if (!CommonSettings.DisableKnownTypesColoring && !settings.LazyClasspathExploration && CurSciControl != null) + // known classes colorization + if (!CommonSettings.DisableKnownTypesColoring && !settings.LazyClasspathExploration && PluginBase.MainForm.CurrentDocument?.SciControl is { } sci) + { + try { - try - { - CurSciControl.KeyWords(1, completionCache.Keywords); // additional-keywords index = 1 - CurSciControl.Colourise(0, -1); // re-colorize the editor - } - catch (AccessViolationException){} // catch memory errors - } + sci.KeyWords(1, completionCache.Keywords); // additional-keywords index = 1 + sci.Colourise(0, -1); // re-colorize the editor + } + catch (AccessViolationException){} // catch memory errors } return completionCache.Elements; } @@ -1249,31 +1202,30 @@ public override MemberList GetAllProjectClasses() if (!completionCache.IsDirty && completionCache.AllTypes != null) return completionCache.AllTypes; - MemberList fullList = new MemberList(); - ClassModel aClass; - MemberModel item; + var result = new MemberList(); // public classes - foreach (PathModel aPath in classPath) if (aPath.IsValid && !aPath.Updating) - { - aPath.ForeachFile((aFile) => + foreach (var aPath in classPath) + if (aPath.IsValid && !aPath.Updating) { - aClass = aFile.GetPublicClass(); - if (!aClass.IsVoid() && aClass.IndexType == null && aClass.Access == Visibility.Public) + aPath.ForeachFile(aFile => { - item = aClass.ToMemberModel(); - item.Name = item.Type; - fullList.Add(item); - } - return true; - }); - } + var aClass = aFile.GetPublicClass(); + if (!aClass.IsVoid() && aClass.IndexType is null && aClass.Access == Visibility.Public) + { + var item = aClass.ToMemberModel(); + item.Name = item.Type; + result.Add(item); + } + return true; + }); + } // void - fullList.Add(new MemberModel(features.voidKey, features.voidKey, FlagType.Class | FlagType.Intrinsic, 0)); + result.Add(new MemberModel(features.voidKey, features.voidKey, FlagType.Class | FlagType.Intrinsic, 0)); // in cache - fullList.Sort(); - completionCache.AllTypes = fullList; - return fullList; + result.Sort(); + completionCache.AllTypes = result; + return result; } public override string GetDefaultValue(string type) => "undefined"; @@ -1281,26 +1233,19 @@ public override MemberList GetAllProjectClasses() #region command line compiler - override public bool CanBuild - { - get { return cFile != null && cFile != FileModel.Ignore; } - } + public override bool CanBuild => cFile != null && cFile != FileModel.Ignore; /// /// Retrieve the context's default compiler path /// - public override string GetCompilerPath() - { - if (as2settings != null) return as2settings.GetDefaultSDK().Path; - else return null; - } + public override string GetCompilerPath() => as2settings?.GetDefaultSDK().Path; /// /// Check current file's syntax /// public override void CheckSyntax() { - if (as2settings == null) + if (as2settings is null) { ErrorManager.ShowInfo(TextHelper.GetString("Info.FeatureMissing")); return; @@ -1312,26 +1257,25 @@ public override void CheckSyntax() /// /// Run MTASC compiler in the current class's base folder with current classpath /// - /// Additional comiler switches + /// Additional compiler switches public override void RunCMD(string append) { - if (as2settings == null) + if (as2settings is null) { ErrorManager.ShowInfo(TextHelper.GetString("Info.FeatureMissing")); return; } - if (!IsFileValid || !File.Exists(CurrentFile)) - return; + if (!IsFileValid || !File.Exists(CurrentFile)) return; if (CurrentModel.Version != 2) { MessageBar.ShowWarning(TextHelper.GetString("Info.InvalidClass")); return; } - string mtascPath = PluginBase.CurrentProject != null - ? PluginBase.CurrentProject.CurrentSDK - : PathHelper.ResolvePath(as2settings.GetDefaultSDK().Path); + var mtascPath = PluginBase.CurrentProject != null + ? PluginBase.CurrentProject.CurrentSDK + : PathHelper.ResolvePath(as2settings.GetDefaultSDK().Path); if (!Directory.Exists(mtascPath) && !File.Exists(mtascPath)) { @@ -1344,31 +1288,28 @@ public override void RunCMD(string append) try { // save modified files if needed - if (outputFile != null) MainForm.CallCommand("SaveAllModified", null); - else MainForm.CallCommand("SaveAllModified", ".as"); - + PluginBase.MainForm.CallCommand("SaveAllModified", outputFile != null ? null : ".as"); + // prepare command string command = mtascPath; if (Path.GetExtension(command) == "") command = Path.Combine(command, "mtasc.exe"); else mtascPath = Path.GetDirectoryName(mtascPath); command += ";\"" + CurrentFile + "\""; - if (append == null || append.IndexOfOrdinal("-swf-version") < 0) - command += " -version "+majorVersion; + if (append is null || !append.Contains("-swf-version")) command += " -version "+majorVersion; // classpathes - foreach(PathModel aPath in classPath) - if (aPath.Path != temporaryPath - && !aPath.Path.StartsWith(mtascPath, StringComparison.OrdinalIgnoreCase)) - command += " -cp \"" + aPath.Path.TrimEnd('\\') + "\""; + foreach(var aPath in classPath) + if (aPath.Path != temporaryPath + && !aPath.Path.StartsWith(mtascPath, StringComparison.OrdinalIgnoreCase)) + command += " -cp \"" + aPath.Path.TrimEnd('\\') + "\""; // run - string filePath = NormalizePath(cFile.BasePath); - if (PluginBase.CurrentProject != null) - filePath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath); - string workDir = MainForm.WorkingDirectory; - MainForm.WorkingDirectory = filePath; - MainForm.CallCommand("RunProcessCaptured", command+" "+append); - MainForm.WorkingDirectory = workDir; + var filePath = NormalizePath(cFile.BasePath); + if (PluginBase.CurrentProject != null) filePath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath); + var workDir = PluginBase.MainForm.WorkingDirectory; + PluginBase.MainForm.WorkingDirectory = filePath; + PluginBase.MainForm.CallCommand("RunProcessCaptured", command+" "+append); + PluginBase.MainForm.WorkingDirectory = workDir; } catch (Exception ex) { @@ -1381,26 +1322,22 @@ public override void RunCMD(string append) /// public override bool BuildCMD(bool failSilently) { - if (as2settings == null) + if (as2settings is null) { ErrorManager.ShowInfo(TextHelper.GetString("Info.FeatureMissing")); return false; } - if (!File.Exists(CurrentFile)) - return false; + if (!File.Exists(CurrentFile)) return false; // check if @mtasc is defined Match mCmd = null; - ClassModel cClass = cFile.GetPublicClass(); + var cClass = cFile.GetPublicClass(); if (IsFileValid && cClass.Comments != null) mCmd = re_CMD_BuildCommand.Match(cClass.Comments); - if (CurrentModel.Version != 2 || mCmd == null || !mCmd.Success) + if (CurrentModel.Version != 2 || mCmd is null || !mCmd.Success) { - if (!failSilently) - { - MessageBar.ShowWarning(TextHelper.GetString("Info.InvalidForQuickBuild")); - } + if (!failSilently) MessageBar.ShowWarning(TextHelper.GetString("Info.InvalidForQuickBuild")); return false; } @@ -1409,11 +1346,10 @@ public override bool BuildCMD(bool failSilently) try { command = Regex.Replace(command, "[\\r\\n]\\s*\\*", "", RegexOptions.Singleline); - command = " " + MainForm.ProcessArgString(command) + " "; + command = " " + PluginBase.MainForm.ProcessArgString(command) + " "; if (string.IsNullOrEmpty(command)) { - if (!failSilently) - throw new Exception(TextHelper.GetString("Info.InvalidQuickBuildCommand")); + if (!failSilently) throw new Exception(TextHelper.GetString("Info.InvalidQuickBuildCommand")); return false; } outputFile = null; @@ -1421,18 +1357,17 @@ public override bool BuildCMD(bool failSilently) trustFileWanted = false; // get SWF url - MatchCollection mPar = re_SplitParams.Matches(command + "-eof"); - int mPlayIndex = -1; - bool noPlay = false; + var mPar = re_SplitParams.Matches(command + "-eof"); + var mPlayIndex = -1; + var noPlay = false; if (mPar.Count > 0) { - string op; for (int i = 0; i < mPar.Count; i++) { - op = mPar[i].Groups["switch"].Value; + var op = mPar[i].Groups["switch"].Value; int start = mPar[i].Index + mPar[i].Length; int end = (mPar.Count > i + 1) ? mPar[i + 1].Index : start; - if ((op == "-swf") && (outputFile == null) && (mPlayIndex < 0)) + if ((op == "-swf") && (outputFile is null) && (mPlayIndex < 0)) { if (end > start) outputFile = command.Substring(start, end - start).Trim(); @@ -1468,24 +1403,21 @@ public override bool BuildCMD(bool failSilently) } } } - if (outputFile.Length == 0) outputFile = null; + if (outputFile.IsNullOrEmpty()) outputFile = null; // cleaning custom switches if (mPlayIndex >= 0) { command = command.Substring(0, mPar[mPlayIndex].Index) + command.Substring(mPar[mPlayIndex + 1].Index); } - if (trustFileWanted) - { - command = command.Replace("-trust", ""); - } + if (trustFileWanted) command = command.Replace("-trust", ""); if (noPlay || !settings.PlayAfterBuild) { command = command.Replace("-noplay", ""); outputFile = null; runAfterBuild = false; } - else runAfterBuild = (outputFile != null); + else runAfterBuild = outputFile != null; // fixing output path if (runAfterBuild) @@ -1514,4 +1446,4 @@ public override bool BuildCMD(bool failSilently) } #endregion } -} +} \ No newline at end of file diff --git a/External/Plugins/AS2Context/PluginMain.cs b/External/Plugins/AS2Context/PluginMain.cs index 875029f90b..0e600c71a2 100644 --- a/External/Plugins/AS2Context/PluginMain.cs +++ b/External/Plugins/AS2Context/PluginMain.cs @@ -15,73 +15,47 @@ namespace AS2Context { public class PluginMain : IPlugin, InstalledSDKOwner { - private String pluginName = "AS2Context"; - private String pluginGuid = "1f387fab-421b-42ac-a985-72a03534f731"; - private String pluginHelp = "www.flashdevelop.org/community/"; - private String pluginDesc = "ActionScript 2 context for the ASCompletion engine."; - private String pluginAuth = "FlashDevelop Team"; - private AS2Settings settingObject; - private Context contextInstance; - private String settingFilename; + AS2Settings settingObject; + Context contextInstance; + string settingFilename; #region Required Properties /// /// Api level of the plugin /// - public Int32 Api - { - get { return 1; } - } + public int Api => 1; /// /// Name of the plugin /// - public String Name - { - get { return this.pluginName; } - } + public string Name { get; } = nameof(AS2Context); /// /// GUID of the plugin /// - public String Guid - { - get { return this.pluginGuid; } - } + public string Guid { get; } = "1f387fab-421b-42ac-a985-72a03534f731"; /// /// Author of the plugin /// - public String Author - { - get { return this.pluginAuth; } - } + public string Author { get; } = "FlashDevelop Team"; /// /// Description of the plugin /// - public String Description - { - get { return this.pluginDesc; } - } + public string Description { get; set; } = "ActionScript 2 context for the ASCompletion engine."; /// /// Web address for help /// - public String Help - { - get { return this.pluginHelp; } - } + public string Help { get; } = "https://www.flashdevelop.org/community/"; /// /// Object that contains the settings /// [Browsable(false)] - public Object Settings - { - get { return this.settingObject; } - } + public object Settings => settingObject; #endregion @@ -92,23 +66,20 @@ public Object Settings /// public void Initialize() { - this.InitBasics(); - this.LoadSettings(); - this.AddEventHandlers(); + InitBasics(); + LoadSettings(); + AddEventHandlers(); } /// /// Disposes the plugin /// - public void Dispose() - { - this.SaveSettings(); - } + public void Dispose() => SaveSettings(); /// /// Handles the incoming events /// - public void HandleEvent(Object sender, NotifyEvent e, HandlingPriority priority) + public void HandleEvent(object sender, NotifyEvent e, HandlingPriority priority) { switch (e.Type) { @@ -130,70 +101,58 @@ public void HandleEvent(Object sender, NotifyEvent e, HandlingPriority priority) /// public void InitBasics() { - String dataPath = Path.Combine(PathHelper.DataDir, "AS2Context"); - if (!Directory.Exists(dataPath)) Directory.CreateDirectory(dataPath); - this.settingFilename = Path.Combine(dataPath, "Settings.fdb"); - this.pluginDesc = TextHelper.GetString("Info.Description"); + var path = Path.Combine(PathHelper.DataDir, nameof(AS2Context)); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + settingFilename = Path.Combine(path, "Settings.fdb"); + Description = TextHelper.GetString("Info.Description"); } /// /// Adds the required event handlers /// - public void AddEventHandlers() - { - EventManager.AddEventHandler(this, EventType.UIStarted); - } + public void AddEventHandlers() => EventManager.AddEventHandler(this, EventType.UIStarted); /// /// Loads the plugin settings /// public void LoadSettings() { - this.settingObject = new AS2Settings(); - if (!File.Exists(this.settingFilename)) this.SaveSettings(); + settingObject = new AS2Settings(); + if (!File.Exists(settingFilename)) SaveSettings(); else { - Object obj = ObjectSerializer.Deserialize(this.settingFilename, this.settingObject); - this.settingObject = (AS2Settings)obj; + settingObject = ObjectSerializer.Deserialize(settingFilename, settingObject); if (settingObject.InstalledSDKs != null) - foreach (InstalledSDK sdk in settingObject.InstalledSDKs) + foreach (var sdk in settingObject.InstalledSDKs) sdk.Owner = this; } - if (this.settingObject.MMClassPath == null) this.settingObject.MMClassPath = FindMMClassPath(); - if (this.settingObject.UserClasspath == null) - { - if (this.settingObject.MMClassPath != null) this.settingObject.UserClasspath = new String[] { this.settingObject.MMClassPath }; - else this.settingObject.UserClasspath = new String[] {}; - } + settingObject.MMClassPath ??= FindMMClassPath(); + settingObject.UserClasspath ??= settingObject.MMClassPath != null + ? new[] {settingObject.MMClassPath} + : Array.Empty(); } /// /// Fix some settings values when the context has been created /// - private void ValidateSettings() + void ValidateSettings() { - if (settingObject.InstalledSDKs == null || settingObject.InstalledSDKs.Length == 0) + if (settingObject.InstalledSDKs.IsNullOrEmpty()) { - List allSdks = new List(); - string includedSDK = "Tools\\mtasc"; + var allSdks = new List(); + var includedSDK = "Tools\\mtasc"; if (Directory.Exists(PathHelper.ResolvePath(includedSDK))) { - InstalledSDK sdk = new InstalledSDK(this); - sdk.Path = includedSDK; - allSdks.Add(sdk); + allSdks.Add(new InstalledSDK(this) {Path = includedSDK}); } - string appManDir = Path.Combine(PathHelper.BaseDir, @"Data\AppMan\Archive\mtasc"); + var appManDir = Path.Combine(PathHelper.BaseDir, @"Data\AppMan\Archive\mtasc"); if (Directory.Exists(appManDir)) { - string[] versionDirs = Directory.GetDirectories(appManDir); - foreach (string versionDir in versionDirs) + var versionDirs = Directory.GetDirectories(appManDir); + foreach (var versionDir in versionDirs) { - if (Directory.Exists(versionDir)) - { - InstalledSDK sdk = new InstalledSDK(this); - sdk.Path = versionDir; - allSdks.Add(sdk); - } + if (!Directory.Exists(versionDir)) continue; + allSdks.Add(new InstalledSDK(this) {Path = versionDir}); } } settingObject.InstalledSDKs = allSdks.ToArray(); @@ -211,18 +170,12 @@ private void ValidateSettings() /// /// Update the classpath if an important setting has changed /// - private void SettingObjectOnClasspathChanged() - { - if (contextInstance != null) contextInstance.BuildClassPath(); - } + void SettingObjectOnClasspathChanged() => contextInstance?.BuildClassPath(); /// /// Saves the plugin settings /// - public void SaveSettings() - { - ObjectSerializer.Serialize(this.settingFilename, this.settingObject); - } + public void SaveSettings() => ObjectSerializer.Serialize(settingFilename, settingObject); #endregion @@ -232,16 +185,15 @@ public bool ValidateSDK(InstalledSDK sdk) { sdk.Owner = this; - IProject project = PluginBase.CurrentProject; - string path = sdk.Path; - if (project != null) - path = PathHelper.ResolvePath(path, Path.GetDirectoryName(project.ProjectPath)); - else - path = PathHelper.ResolvePath(path); + var project = PluginBase.CurrentProject; + var path = sdk.Path; + path = project != null + ? PathHelper.ResolvePath(path, Path.GetDirectoryName(project.ProjectPath)) + : PathHelper.ResolvePath(path); try { - if (path == null || (!Directory.Exists(path) && !File.Exists(path))) + if (!Directory.Exists(path) && !File.Exists(path)) { ErrorManager.ShowInfo("Path not found:\n" + sdk.Path); return false; @@ -254,18 +206,18 @@ public bool ValidateSDK(InstalledSDK sdk) } if (!Directory.Exists(path)) path = Path.GetDirectoryName(path); - string descriptor = Path.Combine(path, "changes.txt"); + var descriptor = Path.Combine(path, "changes.txt"); if (File.Exists(descriptor)) { - string raw = File.ReadAllText(descriptor); - Match mVer = Regex.Match(raw, "[0-9\\-]+\\s*:\\s*([0-9.]+)"); + var text = File.ReadAllText(descriptor); + var mVer = Regex.Match(text, "[0-9\\-]+\\s*:\\s*([0-9.]+)"); if (mVer.Success) { sdk.Version = mVer.Groups[1].Value; - sdk.Name = "MTASC " + sdk.Version; + sdk.Name = $"MTASC {sdk.Version}"; return true; } - else ErrorManager.ShowInfo("Invalid changes.txt file:\n" + descriptor); + ErrorManager.ShowInfo("Invalid changes.txt file:\n" + descriptor); } else ErrorManager.ShowInfo("No changes.txt found:\n" + descriptor); return false; @@ -276,7 +228,7 @@ public bool ValidateSDK(InstalledSDK sdk) #region Macromedia/Adobe Flash IDE // locations in Application Data - static readonly private string[] MACROMEDIA_VERSIONS = { + static readonly string[] MACROMEDIA_VERSIONS = { "\\Adobe\\Flash CS5\\", "\\Adobe\\Flash CS4\\", "\\Adobe\\Flash CS3\\", @@ -287,7 +239,7 @@ public bool ValidateSDK(InstalledSDK sdk) /// /// Explore the possible locations for the Macromedia Flash IDE classpath /// - static private string FindMMClassPath() + static string FindMMClassPath() { bool found = false; string deflang = CultureInfo.CurrentUICulture.Name; @@ -306,7 +258,7 @@ static private string FindMMClassPath() // look for other languages else if (Directory.Exists(cp)) { - string[] dirs = Directory.GetDirectories(cp); + var dirs = Directory.GetDirectories(cp); foreach (string dir in dirs) { if (Directory.Exists(dir + "\\Configuration\\Classes\\")) @@ -319,12 +271,8 @@ static private string FindMMClassPath() } if (found) break; } - if (found) return cp; - else return null; + return found ? cp : null; } #endregion - } - -} - +} \ No newline at end of file diff --git a/External/Plugins/AS3Context/AS3Context.csproj b/External/Plugins/AS3Context/AS3Context.csproj index 8dc029a51c..f73ae9a4b6 100644 --- a/External/Plugins/AS3Context/AS3Context.csproj +++ b/External/Plugins/AS3Context/AS3Context.csproj @@ -1,175 +1,146 @@  - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {0263E5F6-D5B2-4118-B12E-87F9A74DE8AF} - Library - Properties - AS3Context - AS3Context - - - - - 3.5 - - - v4.0 - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - DEBUG;TRACE - prompt - 4 - - - none - true - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - prompt - 4 - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - true - - - - - - - - - - - - - - - - - UserControl - - - ProfilerUI.cs - - - Component - - - - - - - - - False - ..\..\..\FlashDevelop\Bin\Debug\Aga.dll - False - - - False - ..\..\..\FlashDevelop\Bin\Debug\SwfOp.dll - False - - - - - - - - - {61885F70-B4DC-4B44-852D-5D6D03F2A734} - PluginCore - False - - - {74AD0487-CEF9-43FE-9283-BC6F79539ADE} - AS2Context - False - - - {4EBF2653-9654-4E40-880E-0046B3D6210E} - ASCompletion - False - - - {D6AAF434-F4DF-4376-863D-109A8762CECA} - FlashConnect - False - - - {78101C01-E186-4954-B1DD-DEBB7905FAD8} - ProjectManager - False - - - {556F43A0-C288-471A-8CD8-A787FC7ACA34} - XMLCompletion - - - - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - + + + + Debug + AnyCPU + {0263E5F6-D5B2-4118-B12E-87F9A74DE8AF} + Library + Properties + AS3Context + AS3Context + net48 + true + false + false + false + false + x64;x86;AnyCPU + + + true + full + false + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + prompt + 4 + 9 + + + none + true + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + prompt + 4 + 9 + + + x86 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + 9 + + + x86 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + true + 9 + + + true + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + full + x64 + 9 + prompt + + + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + true + x64 + 9 + prompt + + + + + + + + + + + + + + UserControl + + + ProfilerUI.cs + + + Component + + + + + + + + + False + ..\..\..\FlashDevelop\Bin\Debug\Aga.dll + False + + + False + ..\..\..\FlashDevelop\Bin\Debug\SwfOp.dll + False + + + + + + + + + {61885F70-B4DC-4B44-852D-5D6D03F2A734} + PluginCore + False + + + {74AD0487-CEF9-43FE-9283-BC6F79539ADE} + AS2Context + False + + + {4EBF2653-9654-4E40-880E-0046B3D6210E} + ASCompletion + False + + + {D6AAF434-F4DF-4376-863D-109A8762CECA} + FlashConnect + False + + + {78101C01-E186-4954-B1DD-DEBB7905FAD8} + ProjectManager + False + + + {556F43A0-C288-471A-8CD8-A787FC7ACA34} + XMLCompletion + False + + + + + + \ No newline at end of file diff --git a/External/Plugins/AS3Context/AS3Settings.cs b/External/Plugins/AS3Context/AS3Settings.cs index 5bf40464bf..8324303e08 100644 --- a/External/Plugins/AS3Context/AS3Settings.cs +++ b/External/Plugins/AS3Context/AS3Settings.cs @@ -31,8 +31,8 @@ public class AS3Settings : IContextSettings [LocalizedCategory("ASCompletion.Category.Documentation"), LocalizedDescription("ASCompletion.Description.DocumentationCommandLine"), DefaultValue(DEFAULT_DOC_COMMAND)] public string DocumentationCommandLine { - get { return documentationCommandLine; } - set { documentationCommandLine = value; } + get => documentationCommandLine; + set => documentationCommandLine = value; } #endregion @@ -57,46 +57,34 @@ public string DocumentationCommandLine protected bool generateImports = DEFAULT_GENERATEIMPORTS; protected bool playAfterBuild = DEFAULT_PLAY; protected bool fixPackageAutomatically = DEFAULT_FIXPACKAGEAUTOMATICALLY; - protected string[] userClasspath = null; - protected InstalledSDK[] installedSDKs = null; + protected string[] userClasspath; + protected InstalledSDK[] installedSDKs; [Browsable(false)] - public string LanguageId - { - get { return "AS3"; } - } + public string LanguageId => "AS3"; [Browsable(false)] - public string DefaultExtension - { - get { return ".as"; } - } + public string DefaultExtension => ".as"; [Browsable(false)] - public string CheckSyntaxRunning - { - get { return TextHelper.GetString("Info.MxmlcRunning"); } - } + public string CheckSyntaxRunning => TextHelper.GetString("Info.MxmlcRunning"); [Browsable(false)] - public string CheckSyntaxDone - { - get { return TextHelper.GetString("Info.MxmlcDone"); } - } + public string CheckSyntaxDone => TextHelper.GetString("Info.MxmlcDone"); [DisplayName("Check Syntax On Save")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CheckSyntaxOnSave"), DefaultValue(DEFAULT_CHECKSYNTAX)] public bool CheckSyntaxOnSave { - get { return checkSyntaxOnSave; } - set { checkSyntaxOnSave = value; } + get => checkSyntaxOnSave; + set => checkSyntaxOnSave = value; } [DisplayName("User Classpath")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.UserClasspath"), DefaultValue(DEFAULT_AS3LIBRARY)] public string[] UserClasspath { - get { return userClasspath; } + get => userClasspath; set { userClasspath = value; @@ -108,20 +96,18 @@ public string[] UserClasspath [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("AS3Context.Description.FlexSDK")] public InstalledSDK[] InstalledSDKs { - get { return installedSDKs; } + get => installedSDKs; set { installedSDKs = value; FireChanged(); - if (OnInstalledSDKsChanged != null) OnInstalledSDKsChanged(); + OnInstalledSDKsChanged?.Invoke(); } } public InstalledSDK GetDefaultSDK() { - if (installedSDKs == null || installedSDKs.Length == 0) - return InstalledSDK.INVALID_SDK; - + if (installedSDKs.IsNullOrEmpty()) return InstalledSDK.INVALID_SDK; foreach (InstalledSDK sdk in installedSDKs) if (sdk.IsValid) return sdk; return InstalledSDK.INVALID_SDK; @@ -131,56 +117,56 @@ public InstalledSDK GetDefaultSDK() [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CompletionEnabled"), DefaultValue(DEFAULT_COMPLETIONENABLED)] public bool CompletionEnabled { - get { return completionEnabled; } - set { completionEnabled = value; } + get => completionEnabled; + set => completionEnabled = value; } [DisplayName("Generate Imports")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.GenerateImports"), DefaultValue(DEFAULT_GENERATEIMPORTS)] public bool GenerateImports { - get { return generateImports; } - set { generateImports = value; } + get => generateImports; + set => generateImports = value; } [DisplayName("List All Types In Completion")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CompletionListAllTypes"), DefaultValue(DEFAULT_LISTALL)] public bool CompletionListAllTypes { - get { return completionListAllTypes; } - set { completionListAllTypes = value; } + get => completionListAllTypes; + set => completionListAllTypes = value; } [DisplayName("Show Qualified Types In Completion")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.CompletionShowQualifiedTypes"), DefaultValue(DEFAULT_QUALIFY)] public bool CompletionShowQualifiedTypes { - get { return completionShowQualifiedTypes; } - set { completionShowQualifiedTypes = value; } + get => completionShowQualifiedTypes; + set => completionShowQualifiedTypes = value; } [DisplayName("Lazy Classpath Exploration")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.LazyClasspathExploration"), DefaultValue(DEFAULT_LAZYMODE)] public bool LazyClasspathExploration { - get { return lazyClasspathExploration; } - set { lazyClasspathExploration = value; } + get => lazyClasspathExploration; + set => lazyClasspathExploration = value; } [DisplayName("Play After Build")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.PlayAfterBuild"), DefaultValue(DEFAULT_PLAY)] public bool PlayAfterBuild { - get { return playAfterBuild; } - set { playAfterBuild = value; } + get => playAfterBuild; + set => playAfterBuild = value; } [DisplayName("Fix Package Automatically")] [LocalizedCategory("ASCompletion.Category.Common"), LocalizedDescription("ASCompletion.Description.FixPackageAutomatically"), DefaultValue(DEFAULT_FIXPACKAGEAUTOMATICALLY)] public bool FixPackageAutomatically { - get { return fixPackageAutomatically; } - set { fixPackageAutomatically = value; } + get => fixPackageAutomatically; + set => fixPackageAutomatically = value; } #endregion @@ -189,15 +175,15 @@ public bool FixPackageAutomatically const string DEFAULT_FLASHVERSION = "14.0"; - private string flashVersion = DEFAULT_FLASHVERSION; - private string as3ClassPath; - private string[] as3FileTypes; + string flashVersion = DEFAULT_FLASHVERSION; + string as3ClassPath; + string[] as3FileTypes; [DisplayName("Default Flash Version")] [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("AS3Context.Description.DefaultFlashVersion"), DefaultValue(DEFAULT_FLASHVERSION)] public string DefaultFlashVersion { - get { return flashVersion ?? DEFAULT_FLASHVERSION; } + get => flashVersion ?? DEFAULT_FLASHVERSION; set { if (value == flashVersion) return; @@ -211,7 +197,7 @@ public string DefaultFlashVersion [Editor(typeof(VistaFolderNameEditor), typeof(UITypeEditor))] public string AS3ClassPath { - get { return as3ClassPath; } + get => as3ClassPath; set { if (value == as3ClassPath) return; @@ -224,7 +210,7 @@ public string AS3ClassPath [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("AS3Context.Description.AS3FileTypes")] public string[] AS3FileTypes { - get { return as3FileTypes; } + get => as3FileTypes; set { if (value == as3FileTypes) return; @@ -237,23 +223,23 @@ public string[] AS3FileTypes #region Profiler settings const int DEFAULT_PROFILER_TIMEOUT = 30; - private int profilerTimeout; - private string[] customProfilers; + int profilerTimeout; + string[] customProfilers; [DisplayName("Profiler Timeout")] [LocalizedCategory("AS3Context.Category.Profiler"), LocalizedDescription("AS3Context.Description.ProfilerTimeout"), DefaultValue(DEFAULT_PROFILER_TIMEOUT)] public int ProfilerTimeout { - get { return profilerTimeout; } - set { profilerTimeout = Math.Max(5, value); } + get => profilerTimeout; + set => profilerTimeout = Math.Max(5, value); } [DisplayName("Custom Profilers")] [LocalizedCategory("AS3Context.Category.Profiler"), LocalizedDescription("AS3Context.Description.CustomProfilers")] public string[] CustomProfilers { - get { return customProfilers; } - set { customProfilers = value; } + get => customProfilers; + set => customProfilers = value; } #endregion @@ -263,39 +249,39 @@ public string[] CustomProfilers const bool DEFAULT_VERBOSEFDB = false; const bool DEFAULT_DISABLELIVECHECKING = false; - private bool disableFDB; - private bool verboseFDB; - private bool disableLiveChecking; + bool disableFDB; + bool verboseFDB; + bool disableLiveChecking; [DisplayName("Disable Flex Debugger Hosting")] [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("ASCompletion.Description.DisableFDB"), DefaultValue(DEFAULT_DISABLEFDB)] public bool DisableFDB { - get { return disableFDB; } - set { disableFDB = value; } + get => disableFDB; + set => disableFDB = value; } [DisplayName("Verbose Flex Debugger Output")] [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("ASCompletion.Description.VerboseFDB"), DefaultValue(DEFAULT_VERBOSEFDB)] public bool VerboseFDB { - get { return verboseFDB; } - set { verboseFDB = value; } + get => verboseFDB; + set => verboseFDB = value; } [DisplayName("Disable Live Syntax Checking")] [LocalizedCategory("ASCompletion.Category.Language"), LocalizedDescription("ASCompletion.Description.DisableLiveSyntaxChecking"), DefaultValue(DEFAULT_DISABLELIVECHECKING)] public bool DisableLiveChecking { - get { return disableLiveChecking; } - set { disableLiveChecking = value; } + get => disableLiveChecking; + set => disableLiveChecking = value; } #endregion - private void FireChanged() - { - if (OnClasspathChanged != null) OnClasspathChanged(); - } + void FireChanged() => OnClasspathChanged?.Invoke(); + + [Browsable(false)] + public string AddSpaceAfter { get; set; } } } diff --git a/External/Plugins/AS3Context/AbcConverter.cs b/External/Plugins/AS3Context/AbcConverter.cs index baf9039920..fedca48311 100644 --- a/External/Plugins/AS3Context/AbcConverter.cs +++ b/External/Plugins/AS3Context/AbcConverter.cs @@ -17,34 +17,24 @@ namespace AS3Context public class AbcConverter { - static public List ExcludedASDocs = getDefaultExcludedASDocs(); + public static List ExcludedASDocs = new() {"helpid", "keyword"}; - static public Regex reSafeChars = new Regex("[*\\:" + Regex.Escape(new String(Path.GetInvalidPathChars())) + "]", RegexOptions.Compiled); - static private Regex reDocFile = new Regex("[/\\\\]([-_.$a-z0-9]+)\\.xml", RegexOptions.IgnoreCase | RegexOptions.Compiled); + public static Regex reSafeChars = new Regex("[*\\:" + Regex.Escape(new string(Path.GetInvalidPathChars())) + "]", RegexOptions.Compiled); + static readonly Regex reDocFile = new Regex("[/\\\\]([-_.$a-z0-9]+)\\.xml", RegexOptions.IgnoreCase | RegexOptions.Compiled); - static public Dictionary> Docs = new Dictionary>(); + public static Dictionary> Docs = new Dictionary>(); - private static Dictionary genericTypes; - private static Dictionary imports; - private static Dictionary conflicts; - private static bool inSWF; - private static Dictionary thisDocs; - private static string docPath; - - /// - private static List getDefaultExcludedASDocs() - { - List list = new List(); - list.Add("helpid"); - list.Add("keyword"); - return list; - } + static Dictionary genericTypes; + static Dictionary imports; + static Dictionary conflicts; + static bool inSWF; + static Dictionary thisDocs; + static string docPath; /// /// Extract documentation from XML included in ASDocs-enriched SWCs /// - /// - private static void ParseDocumentation(ContentParser parser) + static void ParseDocumentation(ContentParser parser) { if (parser.Catalog != null) { @@ -58,21 +48,17 @@ private static void ParseDocumentation(ContentParser parser) continue; try { - Match m = reDocFile.Match(docFile); + var m = reDocFile.Match(docFile); if (!m.Success) continue; - string package = m.Groups[1].Value; - Dictionary packageDocs = Docs.ContainsKey(package) - ? Docs[package] - : new Dictionary(); - - byte[] rawDoc = parser.Docs[docFile]; - ASDocsReader dr = new ASDocsReader(rawDoc); - dr.ExcludedASDocs = ExcludedASDocs; + var package = m.Groups[1].Value; + if (!Docs.TryGetValue(package, out var packageDocs)) + packageDocs = new Dictionary(); + var rawDoc = parser.Docs[docFile]; + var dr = new ASDocsReader(rawDoc) {ExcludedASDocs = ExcludedASDocs}; dr.Parse(packageDocs); - Docs[package] = packageDocs; } - catch (Exception) + catch { } } @@ -81,7 +67,7 @@ private static void ParseDocumentation(ContentParser parser) /// /// Create virtual FileModel objects from Abc bytecode /// - /// + /// /// /// public static void Convert(ContentParser parser, PathModel path, IASContext context) @@ -92,10 +78,12 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont ParseDocumentation(parser); // extract models - Dictionary models = new Dictionary(); - FileModel privateClasses = new FileModel(Path.Combine(path.Path, "__Private.as")); - privateClasses.Version = 3; - privateClasses.Package = "private"; + var models = new Dictionary(); + var privateClasses = new FileModel(Path.Combine(path.Path, "__Private.as")) + { + Version = 3, + Package = "private" + }; genericTypes = new Dictionary(); imports = new Dictionary(); conflicts = new Dictionary(); @@ -106,8 +94,7 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont foreach (Traits trait in abc.classes) { Traits instance = trait.itraits; - if (instance == null) - continue; + if (instance is null) continue; imports.Clear(); conflicts.Clear(); @@ -116,13 +103,11 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont model.Package = reSafeChars.Replace(instance.name.uri, "_"); model.HasPackage = true; string filename = reSafeChars.Replace(trait.name.ToString(), "_").TrimEnd('$'); - filename = Path.Combine(model.Package.Replace('.', Path.DirectorySeparatorChar), filename); - model.FileName = Path.Combine(path.Path, filename); + model.FileName = Path.Combine(path.Path, model.Package.Replace('.', Path.DirectorySeparatorChar), filename); model.Version = 3; ClassModel type = new ClassModel(); - model.Classes = new List(); - model.Classes.Add(type); + model.Classes = new List {type}; type.InFile = model; type.Type = instance.name.ToTypeString(); @@ -146,20 +131,19 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont if (thisDocs != null) { docPath = (model.Package.Length > 0 ? model.Package + ":" : "globalClassifier:") + type.Name; - if (thisDocs.ContainsKey(docPath)) + if (thisDocs.TryGetValue(docPath, out var doc)) { - ASDocItem doc = thisDocs[docPath]; - applyASDoc(doc, type); + ApplyASDoc(doc, type); if (doc.Meta != null) type.MetaDatas = doc.Meta; } if (model.Package.Length == 0) docPath = type.Name; } - if (instance.baseName.uri == model.Package) - type.ExtendsType = ImportType(instance.baseName.localName); - else type.ExtendsType = ImportType(instance.baseName); + type.ExtendsType = instance.baseName.uri == model.Package + ? ImportType(instance.baseName.localName) + : ImportType(instance.baseName); - if (instance.interfaces != null && instance.interfaces.Length > 0) + if (!instance.interfaces.IsNullOrEmpty()) { type.Implements = new List(); foreach (QName name in instance.interfaces) @@ -185,10 +169,10 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont type.Name = itype[0] + "$" + itype[1]; type.IndexType = itype[1]; } - if (genericTypes.ContainsKey(genType)) + if (genericTypes.TryGetValue(genType, out var inFile)) { model.Classes.Clear(); - type.InFile = genericTypes[genType]; + type.InFile = inFile; genericTypes[genType].Classes.Add(type); } else genericTypes[genType] = model; @@ -211,7 +195,7 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont { // TODO properly support interface multiple inheritance type.ExtendsType = null; - if (type.Implements != null && type.Implements.Count > 0) + if (!type.Implements.IsNullOrEmpty()) { type.ExtendsType = type.Implements[0]; type.Implements.RemoveAt(0); @@ -240,8 +224,6 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont type.Members.Merge(result); type.Constructor = ctor.Name; } - result = null; - temp = null; } else type.Constructor = type.Name; @@ -259,37 +241,31 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont } // packages - if (abc.scripts == null) - continue; - foreach (Traits trait in abc.scripts) + if (abc.scripts is null) continue; + foreach (var trait in abc.scripts) { FileModel model = null; - foreach (MemberInfo info in trait.members) + foreach (var info in trait.members) { - if (info.kind == TraitMember.Class) - continue; - - MemberModel member = GetMember(info, 0); - if (member == null) continue; - - if (model == null || model.Package != info.name.uri) + if (info.kind == TraitMember.Class) continue; + var member = GetMember(info, 0); + if (member is null) continue; + if (model is null || model.Package != info.name.uri) { AddImports(model, imports); - - string package = info.name.uri ?? ""; - string filename = package.Length > 0 ? "package.as" : "toplevel.as"; - filename = Path.Combine(package.Replace('.', Path.DirectorySeparatorChar), filename); - filename = Path.Combine(path.Path, filename); - if (models.ContainsKey(filename)) - model = models[filename]; - else + var package = info.name.uri ?? ""; + var filename = package.Length > 0 ? "package.as" : "toplevel.as"; + filename = Path.Combine(path.Path, package.Replace('.', Path.DirectorySeparatorChar), filename); + if (!models.TryGetValue(filename, out model)) { - model = new FileModel(""); - model.Context = context; - model.Package = package; - model.HasPackage = true; - model.FileName = filename; - model.Version = 3; + model = new FileModel + { + Context = context, + Package = package, + HasPackage = true, + FileName = filename, + Version = 3 + }; models[filename] = model; } } @@ -299,20 +275,17 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont { docPath = "globalOperation:" + (model.Package.Length > 0 ? model.Package + ":" : "") + member.Name; - if (member.Access == Visibility.Public && !String.IsNullOrEmpty(member.Namespace) + if (member.Access == Visibility.Public && !string.IsNullOrEmpty(member.Namespace) && member.Namespace != "public") docPath += member.Namespace + ":"; if ((member.Flags & FlagType.Setter) > 0) docPath += ":set"; else if ((member.Flags & FlagType.Getter) > 0) docPath += ":get"; - - if (thisDocs.ContainsKey(docPath)) applyASDoc(thisDocs[docPath], member); + if (thisDocs.TryGetValue(docPath, out var doc)) ApplyASDoc(doc, member); } - member.InFile = model; member.IsPackageLevel = true; model.Members.Add(member); } - AddImports(model, imports); } } @@ -339,99 +312,82 @@ public static void Convert(ContentParser parser, PathModel path, IASContext cont /// /// old name: setDoc() /// - private static void applyASDoc(ASDocItem doc, MemberModel model) + static void ApplyASDoc(ASDocItem doc, MemberModel model) { model.Comments = doc.LongDesc; - - if (doc.IsFinal) - model.Flags |= FlagType.Final; - - if (doc.IsDynamic && (model is ClassModel)) - model.Flags |= FlagType.Dynamic; - - if (doc.Value != null) - model.Value = doc.Value; - + if (doc.IsFinal) model.Flags |= FlagType.Final; + if (doc.IsDynamic && model is ClassModel) model.Flags |= FlagType.Dynamic; + if (doc.Value != null) model.Value = doc.Value; // TODO Extract features in comments - applyTypeComment(doc, model); - applyTypeCommentToParams(doc, model); + ApplyTypeComment(doc, model); + ApplyTypeCommentToParams(doc, model); } - private static void applyTypeComment(ASDocItem doc, MemberModel model) + static void ApplyTypeComment(ASDocItem doc, MemberModel model) { - if (doc == null || model ==null) - return; - + if (doc is null || model is null) return; ASFileParserUtils.ParseTypeDefinitionInto(doc.ApiType, model, true, true); } - private static void applyTypeCommentToParams(ASDocItem doc, MemberModel model) + static void ApplyTypeCommentToParams(ASDocItem doc, MemberModel model) { - if (doc == null || model == null || model.Parameters == null) - return; - - foreach (MemberModel param in model.Parameters) - if (doc.ParamTypes != null && doc.ParamTypes.ContainsKey(param.Name)) - ASFileParserUtils.ParseTypeDefinitionInto(doc.ParamTypes[param.Name], param, true, true); + if (doc is null || model?.Parameters is null) return; + foreach (var param in model.Parameters) + if (doc.ParamTypes != null && doc.ParamTypes.TryGetValue(param.Name, out var typeDefinition)) + ASFileParserUtils.ParseTypeDefinitionInto(typeDefinition, param, true, true); } - private static void CustomFixes(string path, Dictionary models) + static void CustomFixes(string path, IDictionary models) { - string file = Path.GetFileName(path); - if (file == "playerglobal.swc" || file == "airglobal.swc") + var file = Path.GetFileName(path); + if (file != "playerglobal.swc" && file != "airglobal.swc") return; + var mathPath = Path.Combine(path, "Math"); + if (models.TryGetValue(mathPath, out var model)) { - string mathPath = Path.Combine(path, "Math"); - if (models.ContainsKey(mathPath)) + var @class = model.GetPublicClass(); + foreach (var member in @class.Members) { - ClassModel mathModel = models[mathPath].GetPublicClass(); - foreach (MemberModel member in mathModel.Members) + if (!member.Parameters.IsNullOrEmpty() && member.Parameters[0].Name == "x") { - if (member.Parameters != null && member.Parameters.Count > 0 && member.Parameters[0].Name == "x") + string n = member.Name; + if (member.Parameters.Count > 1) { - string n = member.Name; - if (member.Parameters.Count > 1) - { - if (n == "atan2") member.Parameters.Reverse(); - else if (n == "min" || n == "max") { member.Parameters[0].Name = "val1"; member.Parameters[1].Name = "val2"; } - else if (n == "pow") { member.Parameters[0].Name = "base"; member.Parameters[1].Name = "pow"; } - } - else if (n == "sin" || n == "cos" || n == "tan") member.Parameters[0].Name = "angleRadians"; - else member.Parameters[0].Name = "val"; + if (n == "atan2") member.Parameters.Reverse(); + else if (n == "min" || n == "max") { member.Parameters[0].Name = "val1"; member.Parameters[1].Name = "val2"; } + else if (n == "pow") { member.Parameters[0].Name = "base"; member.Parameters[1].Name = "pow"; } } + else if (n == "sin" || n == "cos" || n == "tan") member.Parameters[0].Name = "angleRadians"; + else member.Parameters[0].Name = "val"; } } - string objPath = Path.Combine(path, "Object"); - if (models.ContainsKey(objPath)) + } + var objPath = Path.Combine(path, "Object"); + if (models.TryGetValue(objPath, out model)) + { + var @class = model.GetPublicClass(); + if (!@class.Members.Contains("prototype")) { - ClassModel objModel = models[objPath].GetPublicClass(); - if (objModel.Members.Search("prototype", 0, 0) == null) - { - MemberModel proto = new MemberModel("prototype", "Object", FlagType.Dynamic | FlagType.Variable, Visibility.Public); - objModel.Members.Add(proto); - } + @class.Members.Add(new MemberModel("prototype", "Object", FlagType.Dynamic | FlagType.Variable, Visibility.Public)); } } } - private static void AddImports(FileModel model, Dictionary imports) + static void AddImports(FileModel model, Dictionary imports) { - if (model != null) - { - foreach (string import in imports.Keys) - model.Imports.Add(new MemberModel(imports[import], import, FlagType.Import, 0)); - - imports.Clear(); - } + if (model is null) return; + foreach (var pair in imports) + model.Imports.Add(new MemberModel(pair.Value, pair.Key, FlagType.Import, 0)); + imports.Clear(); } - private static Dictionary GetDocs(string package) + static Dictionary GetDocs(string package) { - string docPackage = package == "" ? "__Global__" : package; - if (Docs.ContainsKey(docPackage)) return Docs[docPackage]; - else return null; + var docPackage = package == "" ? "__Global__" : package; + Docs.TryGetValue(docPackage, out var result); + return result; } - private static MemberList GetMembers(List abcMembers, FlagType baseFlags, QName instName) + static MemberList GetMembers(IEnumerable abcMembers, FlagType baseFlags, QName instName) { MemberList list = new MemberList(); string package = instName.uri; @@ -440,16 +396,13 @@ private static MemberList GetMembers(List abcMembers, FlagType baseF foreach (MemberInfo info in abcMembers) { MemberModel member = GetMember(info, baseFlags); - if (member == null) continue; + if (member is null) continue; string uri = info.name.uri ?? ""; if (uri.Length > 0) { - if (uri == "private" || package == "private") - { - continue; - } - else if (uri == protect) + if (uri == "private" || package == "private") continue; + if (uri == protect) { member.Access = Visibility.Protected; member.Namespace = "protected"; @@ -492,15 +445,16 @@ private static MemberList GetMembers(List abcMembers, FlagType baseF return list; } - private static MemberModel GetMember(MemberInfo info, FlagType baseFlags) + static MemberModel GetMember(MemberInfo info, FlagType baseFlags) { - MemberModel member = new MemberModel(); - member.Name = info.name.localName; - member.Flags = baseFlags; - member.Access = Visibility.Public; - member.Namespace = "public"; - - if (info.metadata != null && info.metadata.Count > 0) + var member = new MemberModel + { + Name = info.name.localName, + Flags = baseFlags, + Access = Visibility.Public, + Namespace = "public" + }; + if (!info.metadata.IsNullOrEmpty()) { var metadatas = member.MetaDatas; foreach (var metaInfo in info.metadata) @@ -518,39 +472,37 @@ private static MemberModel GetMember(MemberInfo info, FlagType baseFlags) } meta.RawParams = rawParams.ToString(); - if (metadatas == null) metadatas = new List(info.metadata.Count); + metadatas ??= new List(info.metadata.Count); metadatas.Add(meta); } member.MetaDatas = metadatas; } - if (info is SlotInfo) + if (info is SlotInfo slot) { - SlotInfo slot = info as SlotInfo; member.Flags |= FlagType.Variable; if (slot.kind == TraitMember.Const) member.Flags |= FlagType.Constant; - if (slot.value is Namespace) + if (slot.value is Namespace ns) { member.Flags |= FlagType.Namespace; - member.Value = '"' + (slot.value as Namespace).uri + '"'; + member.Value = '"' + ns.uri + '"'; } member.Type = ImportType(slot.type); } - else if (info is MethodInfo) + else if (info is MethodInfo method) { - switch (info.kind) + member.Flags |= method.kind switch { - case TraitMember.Setter: member.Flags |= FlagType.Setter; break; - case TraitMember.Getter: member.Flags |= FlagType.Getter; break; - default: member.Flags |= FlagType.Function; break; - } - MethodInfo method = info as MethodInfo; + TraitMember.Setter => FlagType.Setter, + TraitMember.Getter => FlagType.Getter, + _ => FlagType.Function, + }; QName type = method.returnType; member.Type = ImportType(type); member.Parameters = new List(); int n = method.paramTypes.Length; - int defaultValues = (method.optionalValues != null) ? n - method.optionalValues.Length : n; + int defaultValues = n - method.optionalValues?.Length ?? n; for (int i = 0; i < n; i++) { MemberModel param = new MemberModel(); @@ -570,47 +522,37 @@ private static MemberModel GetMember(MemberInfo info, FlagType baseFlags) member.Parameters.Add(param); } } - else - { - member = null; - } - + else member = null; return member; } - private static void GetMemberDoc(MemberModel member) + static void GetMemberDoc(MemberModel member) { string dPath = docPath + ":"; - if (member.Access == Visibility.Public && !String.IsNullOrEmpty(member.Namespace) + if (member.Access == Visibility.Public && !string.IsNullOrEmpty(member.Namespace) && member.Namespace != "public") dPath += member.Namespace + ":"; dPath += member.Name; if ((member.Flags & FlagType.Getter) > 0) dPath += ":get"; else if ((member.Flags & FlagType.Setter) > 0) dPath += ":set"; - - if (thisDocs.ContainsKey(dPath)) applyASDoc(thisDocs[dPath], member); + if (thisDocs.TryGetValue(dPath, out var doc)) ApplyASDoc(doc, member); } - private static string ImportType(QName type) - { - if (type == null) return "*"; - else return ImportType(type.ToTypeString()); - } + static string ImportType(QName type) => type is null ? "*" : ImportType(type.ToTypeString()); - private static string ImportType(string qname) + static string ImportType(string qname) { - if (qname == null) return "*"; + if (qname is null) return "*"; int p = qname.LastIndexOf('.'); int q = qname.LastIndexOf('<'); if (q > 0) { p = qname.IndexOf('>', q); if (p <= q) return qname; - else - return qname.Substring(0, q + 1) + ImportType(qname.Substring(q + 1, p - q - 1)) + qname.Substring(p); + return qname.Substring(0, q + 1) + ImportType(qname.Substring(q + 1, p - q - 1)) + qname.Substring(p); } if (p < 0) return qname; - if (imports.ContainsKey(qname)) return imports[qname]; + if (imports.TryGetValue(qname, out var import)) return import; string cname = qname.Substring(p + 1); if (!conflicts.ContainsKey(cname)) conflicts.Add(cname, qname); else if (conflicts[cname] != qname) @@ -619,13 +561,16 @@ private static string ImportType(string qname) return cname; } - private static void SetDefaultValue(MemberModel member, object value) + static void SetDefaultValue(MemberModel member, object value) { - if (value == null) member.Value = "null"; - else if (value is string && value.ToString() != "undefined") member.Value = '"' + value.ToString() + '"'; - else if (value is bool) member.Value = value.ToString().ToLower(); - else if (value is double) member.Value = ((double)value).ToString(CultureInfo.InvariantCulture.NumberFormat); - else member.Value = value.ToString(); + member.Value = value switch + { + null => "null", + string _ when value.ToString() != "undefined" => '"' + value.ToString() + '"', + bool _ => value.ToString().ToLower(), + double d => d.ToString(CultureInfo.InvariantCulture.NumberFormat), + _ => value.ToString(), + }; } } @@ -635,16 +580,16 @@ private static void SetDefaultValue(MemberModel member, object value) public class ASDocItem { - public bool IsFinal = false; - public bool IsDynamic = false; - public bool IsStatic = false; + public bool IsFinal; + public bool IsDynamic; + public bool IsStatic; - public string ShortDesc = null; - public string LongDesc = null; - public string Returns = null; - public string Value = null; - public string ApiType = null; - public string DeclType = null; + public string ShortDesc; + public string LongDesc; + public string Returns; + public string Value; + public string ApiType; + public string DeclType; public List Meta; public Dictionary Params = new Dictionary(); @@ -658,8 +603,8 @@ public class ASDocItem class ASDocsReader : XmlTextReader { - public List ExcludedASDocs = null; - private Dictionary docs; + public List ExcludedASDocs; + Dictionary docs; public ASDocsReader(byte[] raw) @@ -685,19 +630,12 @@ public void Parse(Dictionary packageDocs) // PRIMARY //--------------------------- - private void ReadDeclaration(string declType) + void ReadDeclaration(string declType) { - if (IsEmptyElement) - return; - - if (this.ExcludedASDocs == null) - this.ExcludedASDocs = new List(); - - ASDocItem doc = new ASDocItem(); - doc.DeclType = declType; - - string id = GetAttribute("id"); - + if (IsEmptyElement) return; + ExcludedASDocs ??= new List(); + var doc = new ASDocItem {DeclType = declType}; + var id = GetAttribute("id"); if (id != null) { // type doubled in doc: "flash.utils:IDataOutput:flash.utils:IDataOutput:writeDouble" @@ -720,30 +658,27 @@ private void ReadDeclaration(string declType) if (id != null) { - if (doc.ApiType == "String" && doc.Value != null && !doc.Value.StartsWith('\"')) + if (doc.ApiType == "String" && doc.Value != null && !doc.Value.StartsWith('"')) doc.Value = "\"" + doc.Value + "\""; - if (doc.LongDesc == null) - doc.LongDesc = ""; + doc.LongDesc ??= ""; - if (doc.ShortDesc == null) - doc.ShortDesc = doc.LongDesc; - else - doc.LongDesc = doc.LongDesc.Trim(); + if (doc.ShortDesc is null) doc.ShortDesc = doc.LongDesc; + else doc.LongDesc = doc.LongDesc.Trim(); if (doc.LongDesc.Length == 0 && doc.ShortDesc.Length > 0) doc.LongDesc = doc.ShortDesc; - if (!this.ExcludedASDocs.Contains("param") && doc.Params != null) + if (!ExcludedASDocs.Contains("param") && doc.Params != null) foreach (string name in doc.Params.Keys) doc.LongDesc += "\n@param\t" + name + "\t" + doc.Params[name].Trim(); - if (!this.ExcludedASDocs.Contains("return") && doc.Returns != null) + if (!ExcludedASDocs.Contains("return") && doc.Returns != null) doc.LongDesc += "\n@return\t" + doc.Returns.Trim(); if (doc.ExtraAsDocs != null) - foreach (KeyValuePair extraASDoc in doc.ExtraAsDocs) - if (!this.ExcludedASDocs.Contains(extraASDoc.Key)) + foreach (var extraASDoc in doc.ExtraAsDocs) + if (!ExcludedASDocs.Contains(extraASDoc.Key)) doc.LongDesc += "\n@" + extraASDoc.Key + "\t" + extraASDoc.Value; // keep definitions including either documentation or static values @@ -753,16 +688,13 @@ private void ReadDeclaration(string declType) } } - private void ProcessDeclarationNodes(ASDocItem doc) + void ProcessDeclarationNodes(ASDocItem doc) { - if (NodeType != XmlNodeType.Element) - return; - + if (NodeType != XmlNodeType.Element) return; switch (Name) { case "apiName": break; // TODO validate event name case "apiInheritDoc": break; // TODO link inherited doc? - case "apiDetail": case "related-links": SkipContents(); break; @@ -806,7 +738,7 @@ private void ProcessDeclarationNodes(ASDocItem doc) // COMMONS //--------------------------- - private void SkipContents() + void SkipContents() { if (IsEmptyElement) return; @@ -817,7 +749,7 @@ private void SkipContents() Read(); } - private string ReadValue() + string ReadValue() { if (IsEmptyElement) { @@ -831,11 +763,10 @@ private string ReadValue() string prefix = ""; string postfix = ""; string eon = Name; - string lcName; // name in lower case ReadStartElement(); while (Name != eon) { - lcName = Name.ToLower(); + var lcName = Name.ToLower(); // name in lower case if (lcName == "codeblock" || lcName == "listing") { if (NodeType == XmlNodeType.Element) @@ -875,7 +806,7 @@ private string ReadValue() // apiClassifierDetail //--------------------------- - private void ReadApiClassifierDetail(ASDocItem doc) + void ReadApiClassifierDetail(ASDocItem doc) { doc.LongDesc = ""; @@ -894,23 +825,23 @@ private void ReadApiClassifierDetail(ASDocItem doc) break; case "apiDesc": - doc.LongDesc += this.ReadInnerXml() +"\n"; + doc.LongDesc += ReadInnerXml() +"\n"; // Read(); break; case "example": - doc.LongDesc += "\nEXAMPLE: \n\n" + this.ReadInnerXml() +"\n"; + doc.LongDesc += "\nEXAMPLE: \n\n" + ReadInnerXml() +"\n"; // Read(); break; default: - this.ReadInnerXml(); + ReadInnerXml(); break; } } } - private void ReadApiClassifierDef(ASDocItem doc) + void ReadApiClassifierDef(ASDocItem doc) { if (IsEmptyElement) return; @@ -954,7 +885,7 @@ private void ReadApiClassifierDef(ASDocItem doc) /// --- /// /// - private void ReadProlog(ASDocItem doc) + void ReadProlog(ASDocItem doc) { if (IsEmptyElement) return; @@ -972,7 +903,7 @@ private void ReadProlog(ASDocItem doc) } } - private void ReadPrologMetadata(ASDocItem doc) + void ReadPrologMetadata(ASDocItem doc) { if (IsEmptyElement) return; @@ -991,18 +922,17 @@ private void ReadPrologMetadata(ASDocItem doc) } } - private void ReadPrologMetadataApiVersion(ASDocItem doc) + void ReadPrologMetadataApiVersion(ASDocItem doc) { if (IsEmptyElement) return; - string asdocKey; - string asdocVal; - string eon = Name; ReadStartElement(); while (Name != eon) { + string asdocVal; + string asdocKey; if (Name == "apiLanguage") { string sVers = GetAttribute("version"); @@ -1039,7 +969,7 @@ private void ReadPrologMetadataApiVersion(ASDocItem doc) } } - private void ReadPrologMetadataStyles(ASDocItem doc) + void ReadPrologMetadataStyles(ASDocItem doc) { if (IsEmptyElement) return; @@ -1054,7 +984,7 @@ private void ReadPrologMetadataStyles(ASDocItem doc) } } - private void ReadPrologMetadataDefaultProperty(ASDocItem doc) + void ReadPrologMetadataDefaultProperty(ASDocItem doc) { ASMetaData meta = new ASMetaData("DefaultProperty"); meta.Kind = ASMetaKind.DefaultProperty; @@ -1065,25 +995,22 @@ private void ReadPrologMetadataDefaultProperty(ASDocItem doc) string defValue = GetAttribute("name"); meta.Params["default"] = defValue; - meta.RawParams = string.Format("\"{0}\"", defValue); + meta.RawParams = $"\"{defValue}\""; - if (doc.Meta == null) doc.Meta = new List(); + doc.Meta ??= new List(); doc.Meta.Add(meta); } - private void ReadPrologCustoms(ASDocItem doc, string terminationNode) + void ReadPrologCustoms(ASDocItem doc, string terminationNode) { if (IsEmptyElement) return; - string asdocKey; - string asdocVal; - string eon = terminationNode; ReadStartElement(); while (!(Name == eon && NodeType == XmlNodeType.EndElement)) { - asdocKey = this.Name; + var asdocKey = Name; /* if (asdocKey == "maelexample") @@ -1094,7 +1021,7 @@ private void ReadPrologCustoms(ASDocItem doc, string terminationNode) else { */ - asdocVal = this.ReadInnerXml(); + var asdocVal = ReadInnerXml(); // } doc.ExtraAsDocs.Add(new KeyValuePair(asdocKey, asdocVal)); @@ -1106,27 +1033,17 @@ private void ReadPrologCustoms(ASDocItem doc, string terminationNode) // apiType //--------------------------- - private void ReadApiType(ASDocItem doc) - { - SetApiType(doc, GetAttribute("value")); - } - - private void ReadApiTypeAsClassifier(ASDocItem doc) - { - SetApiType(doc, ReadValue()); - } - - private void SetApiType(ASDocItem doc, string apiType) - { - doc.ApiType = apiType == "any" ? "*" : apiType; - } + void ReadApiType(ASDocItem doc) => SetApiType(doc, GetAttribute("value")); + void ReadApiTypeAsClassifier(ASDocItem doc) => SetApiType(doc, ReadValue()); + static void SetApiType(ASDocItem doc, string apiType) => doc.ApiType = apiType == "any" ? "*" : apiType; + //--------------------------- // apiOperationDetail //--------------------------- - private void ReadParamDesc(ASDocItem doc) + void ReadParamDesc(ASDocItem doc) { if (IsEmptyElement) return; @@ -1169,7 +1086,7 @@ private void ReadParamDesc(ASDocItem doc) } } - private void ReadReturnsDesc(ASDocItem doc) + void ReadReturnsDesc(ASDocItem doc) { if (IsEmptyElement) return; @@ -1178,7 +1095,7 @@ private void ReadReturnsDesc(ASDocItem doc) ReadStartElement(); while (Name != eon) { - switch (this.Name) + switch (Name) { case "apiDesc": doc.Returns = ReadValue(); @@ -1202,14 +1119,13 @@ private void ReadReturnsDesc(ASDocItem doc) // apiException //--------------------------- - private void ReadApiException(ASDocItem doc) + void ReadApiException(ASDocItem doc) { if (IsEmptyElement) return; string apiDesc = ""; string apiItemName = ""; - string apiOperationClassifier = ""; string eon = Name; ReadStartElement(); @@ -1226,7 +1142,7 @@ private void ReadApiException(ASDocItem doc) break; case "apiOperationClassifier": - apiOperationClassifier = ReadValue(); + ReadValue(); break; } Read(); @@ -1240,24 +1156,21 @@ private void ReadApiException(ASDocItem doc) // Meta tags //--------------------------- - private void ReadExcludeMeta(ASDocItem doc) + void ReadExcludeMeta(ASDocItem doc) { if (!HasAttributes) return; - ASMetaData meta = new ASMetaData("Style"); - meta.Kind = ASMetaKind.Exclude; + ASMetaData meta = new ASMetaData("Style") {Kind = ASMetaKind.Exclude}; string sKind = GetAttribute("kind"); string sName = GetAttribute("name"); - if (doc.Meta == null) doc.Meta = new List(); - meta.Params = new Dictionary(); - meta.Params["kind"] = sKind; - meta.Params["name"] = sName; - meta.RawParams = String.Format("kind=\"{0}\", name=\"{1}\"", sKind, sName); + doc.Meta ??= new List(); + meta.Params = new Dictionary {["kind"] = sKind, ["name"] = sName}; + meta.RawParams = $"kind=\"{sKind}\", name=\"{sName}\""; doc.Meta.Add(meta); } - private void ReadStyleMeta(ASDocItem doc) + void ReadStyleMeta(ASDocItem doc) { if (IsEmptyElement || !HasAttributes) return; @@ -1285,12 +1198,10 @@ private void ReadStyleMeta(ASDocItem doc) Read(); } - if (doc.Meta == null) doc.Meta = new List(); + doc.Meta ??= new List(); if (sDefault != null) meta.Comments = meta.Comments.Trim() + "\n@default\t" + sDefault; - meta.Params = new Dictionary(); - meta.Params["name"] = sName; - meta.Params["type"] = sType; - meta.RawParams = String.Format("name=\"{0}\", type=\"{1}\"", sName, sType); + meta.Params = new Dictionary {["name"] = sName, ["type"] = sType}; + meta.RawParams = $"name=\"{sName}\", type=\"{sType}\""; if (sInherit != null) { meta.Params["inherit"] = sInherit; @@ -1304,7 +1215,7 @@ private void ReadStyleMeta(ASDocItem doc) doc.Meta.Add(meta); } - private void ReadEventMeta(ASDocItem doc) + void ReadEventMeta(ASDocItem doc) { if (IsEmptyElement) return; @@ -1331,13 +1242,11 @@ private void ReadEventMeta(ASDocItem doc) Read(); } - if (doc.Meta == null) doc.Meta = new List(); - meta.Params = new Dictionary(); - meta.Params["name"] = eName; - meta.Params["type"] = eType; + doc.Meta ??= new List(); + meta.Params = new Dictionary {["name"] = eName, ["type"] = eType}; if (eFullType != null) meta.Comments = meta.Comments.Trim() + "\n@eventType\t" + eFullType.Replace(':', '.'); - meta.RawParams = String.Format("name=\"{0}\", type=\"{1}\"", eName, eType); + meta.RawParams = $"name=\"{eName}\", type=\"{eType}\""; doc.Meta.Add(meta); } } diff --git a/External/Plugins/AS3Context/Compiler/FdbWrapper.cs b/External/Plugins/AS3Context/Compiler/FdbWrapper.cs index 9086e9bc2f..84e22c343c 100644 --- a/External/Plugins/AS3Context/Compiler/FdbWrapper.cs +++ b/External/Plugins/AS3Context/Compiler/FdbWrapper.cs @@ -21,17 +21,18 @@ public class FdbWrapper public void Run(string projectPath, string flexSDKPath) { flexSDKPath = PathHelper.ResolvePath(flexSDKPath, projectPath); - if (flexSDKPath != null && Directory.Exists(flexSDKPath)) + if (Directory.Exists(flexSDKPath)) { if (flexSDKPath.EndsWith("bin", StringComparison.OrdinalIgnoreCase)) flexSDKPath = Path.GetDirectoryName(flexSDKPath); } else return; - Dictionary jvmConfig = JvmConfigHelper.ReadConfig(flexSDKPath); - - if (process == null || process.HasExited) + if (process is null || process.HasExited) + { + var jvmConfig = JvmConfigHelper.ReadConfig(flexSDKPath); Initialize(flexSDKPath, jvmConfig, projectPath); + } } public void PushCommand(string cmd) @@ -64,7 +65,7 @@ bool Initialize(string flexSDKPath, Dictionary jvmConfig, string { cmdQueue = new Queue(); - string fdbPath = Path.Combine(flexSDKPath, "lib\\fdb.jar"); + var fdbPath = Path.Combine(flexSDKPath, "lib\\fdb.jar"); if (!File.Exists(fdbPath)) fdbPath = Path.Combine(flexSDKPath, "lib\\legacy\\fdb.jar"); if (!File.Exists(fdbPath)) { @@ -102,7 +103,7 @@ void process_Exited(object sender, EventArgs e) { keepAlive = false; Cleanup(); - if (OnOutput != null) OnOutput("[FDB halted]"); + OnOutput?.Invoke("[FDB halted]"); } public void Cleanup() @@ -111,7 +112,7 @@ public void Cleanup() if (process != null && !process.HasExited && keepAlive) { keepAlive = false; - if (OnOutput != null) OnOutput("[Shutting down FDB]"); + OnOutput?.Invoke("[Shutting down FDB]"); try { if (!process.HasExited) process.Kill(); @@ -146,7 +147,7 @@ void FdbRun() running = true; WriteToPrompt("run"); Thread.Sleep(200); - if (OnStarted != null) OnStarted(null); + OnStarted?.Invoke(null); } // send commands queue else if (cmdQueue.Count > 0) WriteToPrompt(cmdQueue.Dequeue()); @@ -161,7 +162,7 @@ void FdbRun() } if (process != null && !process.HasExited) { - if (OnOutput != null) OnOutput("[Shutting down FDB]"); + OnOutput?.Invoke("[Shutting down FDB]"); try { if (!process.HasExited) process.Kill(); @@ -175,16 +176,15 @@ void ReadErrors() while (keepAlive && !process.StandardError.EndOfStream) { string line = process.StandardError.ReadLine(); - if (OnError != null) OnError(line); + OnError?.Invoke(line); } } void WriteToPrompt(string line) { interactive = false; - if (process != null) - process.StandardInput.WriteLine(line); - if (OnOutput != null) OnOutput("(fdb) "+line); + process?.StandardInput.WriteLine(line); + OnOutput?.Invoke("(fdb) "+line); } /// @@ -199,14 +199,12 @@ void ReadUntilPrompt() void ReadUntilToken(string token) { - StringBuilder output = new StringBuilder(); - Queue queue = new Queue(); - - bool keepProcessing = true; + var output = new StringBuilder(); + var queue = new Queue(); + var keepProcessing = true; while (keepProcessing && keepAlive) { - if (process == null || process.HasExited) - keepProcessing = false; + if (process is null || process.HasExited) keepProcessing = false; else { char c = (char)process.StandardOutput.Read(); @@ -233,12 +231,12 @@ void ReadUntilToken(string token) #region Understanding - static Regex reTrace = new Regex(@"^?\[trace\]", RegexOptions.Compiled); - static Regex reFault = new Regex(@"^(\[Fault\]|Fault,) ", RegexOptions.Compiled); - static Regex reLoad = new Regex(@"^\[SWF\] ", RegexOptions.Compiled); - static Regex reUnload = new Regex(@"^\[UnloadSWF\] ", RegexOptions.Compiled); - static Regex reDisconnect = new Regex(@"^Player session terminated", RegexOptions.Compiled); - static Regex reContinue = new Regex(@"'continue'", RegexOptions.Compiled); + static readonly Regex reTrace = new Regex(@"^?\[trace\]", RegexOptions.Compiled); + static readonly Regex reFault = new Regex(@"^(\[Fault\]|Fault,) ", RegexOptions.Compiled); + static readonly Regex reLoad = new Regex(@"^\[SWF\] ", RegexOptions.Compiled); + static readonly Regex reUnload = new Regex(@"^\[UnloadSWF\] ", RegexOptions.Compiled); + static readonly Regex reDisconnect = new Regex(@"^Player session terminated", RegexOptions.Compiled); + static readonly Regex reContinue = new Regex(@"'continue'", RegexOptions.Compiled); void MatchLine(string line) { @@ -253,11 +251,11 @@ void MatchLine(string line) // [trace] Hello World! else if (reTrace.IsMatch(line)) { - if (OnTrace != null) + if (OnTrace is { } onTrace) { - string trace = line.Substring(line.IndexOf(']') + 1); - if (trace.Length > 0 && Char.IsWhiteSpace(trace[0])) OnTrace(trace.Substring(1)); - else OnTrace(trace); + var trace = line.Substring(line.IndexOf(']') + 1); + if (trace.Length > 0 && char.IsWhiteSpace(trace[0])) onTrace(trace.Substring(1)); + else onTrace(trace); return; } } @@ -266,9 +264,9 @@ void MatchLine(string line) // 20 else if (reFault.IsMatch(line)) { - if (OnError != null) + if (OnError is { } onError) { - OnError(line); + onError(line); return; } } @@ -290,7 +288,7 @@ void MatchLine(string line) keepAlive = false; } - if (OnOutput != null) OnOutput(line); + OnOutput?.Invoke(line); } #endregion } diff --git a/External/Plugins/AS3Context/Compiler/FlexDebugger.cs b/External/Plugins/AS3Context/Compiler/FlexDebugger.cs index 8aea4fab92..4f237848b3 100644 --- a/External/Plugins/AS3Context/Compiler/FlexDebugger.cs +++ b/External/Plugins/AS3Context/Compiler/FlexDebugger.cs @@ -13,14 +13,14 @@ public static bool Start(string projectPath, string flex2Path, DataEvent message if (ignoreMessage) return false; try { - if (debugger != null) debugger.Cleanup(); + debugger?.Cleanup(); startMessage = message; debugger = new FdbWrapper(); - debugger.OnStarted += new LineEvent(debugger_OnStarted); - debugger.OnTrace += new LineEvent(debugger_OnTrace); - debugger.OnError += new LineEvent(debugger_OnError); + debugger.OnStarted += debugger_OnStarted; + debugger.OnTrace += debugger_OnTrace; + debugger.OnError += debugger_OnError; if (PluginMain.Settings.VerboseFDB) - debugger.OnOutput += new LineEvent(debugger_OnOutput); + debugger.OnOutput += debugger_OnOutput; debugger.Run(projectPath, flex2Path); TraceManager.AddAsync(TextHelper.GetString("Info.CapturingTracesWithFDB")); return true; @@ -45,14 +45,13 @@ public static void Stop() #endregion - static private bool ignoreMessage; - static private FdbWrapper debugger; - static private DataEvent startMessage; + static bool ignoreMessage; + static FdbWrapper debugger; + static DataEvent startMessage; static void debugger_OnStarted(string line) { - if (startMessage == null) - return; + if (startMessage is null) return; PluginBase.RunAsync(delegate { // send message again @@ -63,19 +62,10 @@ static void debugger_OnStarted(string line) }); } - static void debugger_OnError(string line) - { - TraceManager.AddAsync(line, 3); - } + static void debugger_OnError(string line) => TraceManager.AddAsync(line, 3); - static void debugger_OnOutput(string line) - { - TraceManager.AddAsync(line, 1); - } + static void debugger_OnOutput(string line) => TraceManager.AddAsync(line, 1); - static void debugger_OnTrace(string line) - { - TraceManager.AddAsync(line, 1); - } + static void debugger_OnTrace(string line) => TraceManager.AddAsync(line, 1); } } diff --git a/External/Plugins/AS3Context/Compiler/FlexShells.cs b/External/Plugins/AS3Context/Compiler/FlexShells.cs index d239dcc5d7..58c8e7527c 100644 --- a/External/Plugins/AS3Context/Compiler/FlexShells.cs +++ b/External/Plugins/AS3Context/Compiler/FlexShells.cs @@ -24,12 +24,12 @@ namespace AS3Context.Compiler /// public class FlexShells { - static public event SyntaxErrorHandler SyntaxError; + public static event SyntaxErrorHandler SyntaxError; - static readonly public Regex re_SplitParams = + public static readonly Regex re_SplitParams = new Regex("[\\s](?[-+][A-z0-9\\-\\.]+)", RegexOptions.Compiled | RegexOptions.Singleline); - static private readonly string[] PATH_SWITCHES = { + static readonly string[] PATH_SWITCHES = { "-compiler.context-root","-context-root", "-compiler.defaults-css-url","-defaults-css-url", "-compiler.external-library-path","-external-library-path","-el", @@ -43,78 +43,59 @@ public class FlexShells "-link-report","-load-config","-load-externs","-size-report", "-output","-o","-runtime-shared-libraries","-rsl", "-namespace","-compiler.namespaces.namespace"}; - - static private string ascPath; - static private string mxmlcPath; - static private string flexShellsJar = "Flex4Shells.jar"; - static private string flexShellsPath; - static private bool running; - static private bool silentChecking; - static private string checkedSDK; - static private bool isFlex4SDK; - static private string currentSDK; - - static private string CheckResource(string resName, string fileName) + + static string ascPath; + static string mxmlcPath; + static readonly string flexShellsJar = "Flex4Shells.jar"; + static string flexShellsPath; + static bool running; + static bool silentChecking; + static string checkedSDK; + static bool isFlex4SDK; + static string currentSDK; + + static string CheckResource(string resName, string fileName) { - string path = Path.Combine(PathHelper.DataDir, "AS3Context"); - string fullPath = Path.Combine(path, fileName); - if (!File.Exists(fullPath)) + var fullPath = Path.Combine(PathHelper.DataDir, "AS3Context", fileName); + if (File.Exists(fullPath)) return fullPath; + var id = "AS3Context.Resources." + resName; + var assembly = Assembly.GetExecutingAssembly(); + using var br = new BinaryReader(assembly.GetManifestResourceStream(id)); + using var bw = File.Create(fullPath); + var buffer = br.ReadBytes(1024); + while (buffer.Length > 0) { - string id = "AS3Context.Resources." + resName; - Assembly assembly = Assembly.GetExecutingAssembly(); - using (BinaryReader br = new BinaryReader(assembly.GetManifestResourceStream(id))) - { - using (FileStream bw = File.Create(fullPath)) - { - byte[] buffer = br.ReadBytes(1024); - while (buffer.Length > 0) - { - bw.Write(buffer, 0, buffer.Length); - buffer = br.ReadBytes(1024); - } - bw.Close(); - } - br.Close(); - } + bw.Write(buffer, 0, buffer.Length); + buffer = br.ReadBytes(1024); } + bw.Close(); + br.Close(); return fullPath; } - static public FlexShells Instance - { - get { - if (instance == null) instance = new FlexShells(); - return instance; - } - } - - static private FlexShells instance; + public static FlexShells Instance => instance ??= new FlexShells(); - private FlexShells() + static FlexShells instance; + + FlexShells() { } - private ProcessRunner ascRunner; - private ProcessRunner mxmlcRunner; - private string builtSWF; - private bool debugMode; - private Dictionary jvmConfig; + ProcessRunner ascRunner; + ProcessRunner mxmlcRunner; + string builtSWF; + bool debugMode; + Dictionary jvmConfig; - public void CheckAS3(string filename, string flexPath) - { - CheckAS3(filename, flexPath, null); - } + public void CheckAS3(string filename, string flexPath) => CheckAS3(filename, flexPath, null); public void CheckAS3(string filename, string flexPath, string src) { if (running) return; // let other plugins preprocess source/handle checking - Hashtable data = new Hashtable(); - data["filename"] = filename; - data["src"] = src; - data["ext"] = Path.GetExtension(filename); - DataEvent de = new DataEvent(EventType.Command, "AS3Context.CheckSyntax", data); + var data = new Hashtable {["filename"] = filename, ["src"] = src, ["ext"] = Path.GetExtension(filename)}; + var de = new DataEvent(EventType.Command, "AS3Context.CheckSyntax", data); EventManager.DispatchEvent(this, de); if (de.Handled) return; @@ -124,29 +105,27 @@ public void CheckAS3(string filename, string flexPath, string src) return; string basePath = null; - if (PluginBase.CurrentProject != null) - basePath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath); + if (PluginBase.CurrentProject != null) basePath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath); flexPath = PathHelper.ResolvePath(flexPath, basePath); // asc.jar in FlexSDK if (flexPath != null && Directory.Exists(Path.Combine(flexPath, "lib"))) ascPath = Path.Combine(flexPath, "lib\\asc.jar"); // included asc.jar - if (ascPath == null || !File.Exists(ascPath)) - ascPath = PathHelper.ResolvePath(Path.Combine(PathHelper.ToolDir, "flexlibs/lib/asc.jar")); - - if (ascPath == null) + if (!File.Exists(ascPath)) ascPath = PathHelper.ResolvePath(Path.Combine(PathHelper.ToolDir, "flexlibs/lib/asc.jar")); + if (ascPath is null) { if (src != null) return; // silent checking - DialogResult result = MessageBox.Show(TextHelper.GetString("Info.SetFlex2OrCS3Path"), TextHelper.GetString("Title.ConfigurationRequired"), MessageBoxButtons.YesNoCancel); - if (result == DialogResult.Yes) + var result = MessageBox.Show(TextHelper.GetString("Info.SetFlex2OrCS3Path"), TextHelper.GetString("Title.ConfigurationRequired"), MessageBoxButtons.YesNoCancel); + switch (result) { - IASContext context = ASContext.GetLanguageContext("as3"); - if (context == null) return; - PluginBase.MainForm.ShowSettingsDialog("AS3Context", "SDK"); - } - else if (result == DialogResult.No) - { - PluginBase.MainForm.ShowSettingsDialog("ASCompletion", "Flash"); + case DialogResult.Yes: + var context = ASContext.GetLanguageContext("as3"); + if (context is null) return; + PluginBase.MainForm.ShowSettingsDialog("AS3Context", "SDK"); + break; + case DialogResult.No: + PluginBase.MainForm.ShowSettingsDialog("ASCompletion", "Flash"); + break; } return; } @@ -164,12 +143,10 @@ public void CheckAS3(string filename, string flexPath, string src) try { running = true; - if (src == null) EventManager.DispatchEvent(this, new NotifyEvent(EventType.ProcessStart)); - if (ascRunner == null || !ascRunner.IsRunning || currentSDK != flexPath) - StartAscRunner(flexPath); - + if (src is null) EventManager.DispatchEvent(this, new NotifyEvent(EventType.ProcessStart)); + if (ascRunner is null || !ascRunner.IsRunning || currentSDK != flexPath) StartAscRunner(flexPath); notificationSent = false; - if (src == null) + if (src is null) { silentChecking = false; //TraceManager.Add("Checking: " + filename, -1); @@ -195,23 +172,17 @@ public void RunMxmlc(string cmd, string flexPath) { if (running) return; string basePath = null; - if (PluginBase.CurrentProject != null) - basePath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath); + if (PluginBase.CurrentProject != null) basePath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath); flexPath = PathHelper.ResolvePath(flexPath, basePath); - if (flexPath != null && Directory.Exists(flexPath)) - { - mxmlcPath = Path.Combine(Path.Combine(flexPath, "lib"), "mxmlc.jar"); - } - if (mxmlcPath == null || !File.Exists(mxmlcPath)) + if (Directory.Exists(flexPath)) mxmlcPath = Path.Combine(flexPath, "lib", "mxmlc.jar"); + if (!File.Exists(mxmlcPath)) { - DialogResult result = MessageBox.Show(TextHelper.GetString("Info.OpenCompilerSettings"), TextHelper.GetString("Title.ConfigurationRequired"), MessageBoxButtons.OKCancel); - if (result == DialogResult.OK) - { - IASContext context = ASContext.GetLanguageContext("as3"); - if (context == null) return; - PluginBase.MainForm.ShowSettingsDialog("AS3Context", "SDK"); - } + var result = MessageBox.Show(TextHelper.GetString("Info.OpenCompilerSettings"), TextHelper.GetString("Title.ConfigurationRequired"), MessageBoxButtons.OKCancel); + if (result != DialogResult.OK) return; + var context = ASContext.GetLanguageContext("as3"); + if (context is null) return; + PluginBase.MainForm.ShowSettingsDialog("AS3Context", "SDK"); return; } @@ -229,7 +200,7 @@ public void RunMxmlc(string cmd, string flexPath) running = true; EventManager.DispatchEvent(this, new NotifyEvent(EventType.ProcessStart)); - if (mxmlcRunner == null || !mxmlcRunner.IsRunning || currentSDK != flexPath) + if (mxmlcRunner is null || !mxmlcRunner.IsRunning || currentSDK != flexPath) StartMxmlcRunner(flexPath); //cmd = mainForm.ProcessArgString(cmd); @@ -261,30 +232,27 @@ public void QuickBuild(FileModel theFile, string flex2Path, bool requireTag, boo } // command debugMode = false; - bool hasOutput = false; - string cmd = ""; - Match mCmd = Regex.Match(PluginBase.MainForm.CurrentDocument.SciControl.Text, "\\s@mxmlc\\s(?.*)"); + var hasOutput = false; + var cmd = ""; + var mCmd = Regex.Match(PluginBase.MainForm.CurrentDocument?.SciControl.Text, "\\s@mxmlc\\s(?.*)"); if (mCmd.Success) { try { - // cleanup tag - string tag = mCmd.Groups["cmd"].Value; + var tag = mCmd.Groups["cmd"].Value; if (tag.IndexOfOrdinal("-->") > 0) tag = tag.Substring(0, tag.IndexOfOrdinal("-->")); if (tag.IndexOfOrdinal("]]>") > 0) tag = tag.Substring(0, tag.IndexOfOrdinal("]]>")); tag = " " + tag.Trim() + " --"; // split - MatchCollection mPar = re_SplitParams.Matches(tag); + var mPar = re_SplitParams.Matches(tag); if (mPar.Count > 0) { cmd = ""; - string op; - string arg; for (int i = 0; i < mPar.Count; i++) { - op = mPar[i].Groups["switch"].Value; + var op = mPar[i].Groups["switch"].Value; if (op == "--") break; if (op == "-noplay") { @@ -298,7 +266,7 @@ public void QuickBuild(FileModel theFile, string flex2Path, bool requireTag, boo if (end > start) { string concat = ";"; - arg = tag.Substring(start, end - start).Trim(); + var arg = tag.Substring(start, end - start).Trim(); if (arg.StartsWithOrdinal("+=") || arg.StartsWith('=')) { concat = arg.Substring(0, arg.IndexOf('=') + 1); @@ -347,13 +315,13 @@ public void QuickBuild(FileModel theFile, string flex2Path, bool requireTag, boo else if (requireTag) return; // Flex4 static linking - if (isFlex4SDK && cmd.IndexOfOrdinal("-static-link-runtime-shared-libraries") < 0) + if (isFlex4SDK && !cmd.Contains("-static-link-runtime-shared-libraries")) cmd += ";-static-link-runtime-shared-libraries=true"; // add current class sourcepath and global classpaths cmd += ";-sp+=" + theFile.BasePath; - if (Context.Context.Settings.UserClasspath != null) - foreach (string cp in Context.Context.Settings.UserClasspath) + if (ASContext.Context.Settings.UserClasspath != null) + foreach (string cp in ASContext.Context.Settings.UserClasspath) cmd += ";-sp+=" + cp; // add output filename if (!hasOutput) @@ -373,7 +341,7 @@ public void QuickBuild(FileModel theFile, string flex2Path, bool requireTag, boo Environment.CurrentDirectory = currentPath; } - private void CheckIsFlex4SDK(string flexPath) + void CheckIsFlex4SDK(string flexPath) { if (checkedSDK == flexPath) return; checkedSDK = flexPath; @@ -417,7 +385,7 @@ public void Stop() /// /// Start background process /// - private void StartAscRunner(string flexPath) + void StartAscRunner(string flexPath) { currentSDK = flexPath; if (ascRunner != null && ascRunner.IsRunning) ascRunner.KillProcess(); @@ -440,7 +408,7 @@ private void StartAscRunner(string flexPath) /// /// Start background process /// - private void StartMxmlcRunner(string flexPath) + void StartMxmlcRunner(string flexPath) { currentSDK = flexPath; if (mxmlcRunner != null && mxmlcRunner.IsRunning) mxmlcRunner.KillProcess(); @@ -467,11 +435,11 @@ private void StartMxmlcRunner(string flexPath) #region process output capture - private int errorState; - private string errorDesc; - private bool notificationSent; + int errorState; + string errorDesc; + bool notificationSent; - private void ascRunner_Error(object sender, string line) + void ascRunner_Error(object sender, string line) { if (line.StartsWithOrdinal("[Compiler] Error")) { @@ -481,10 +449,10 @@ private void ascRunner_Error(object sender, string line) else if (errorState == 1) { line = line.Trim(); - Match mErr = Regex.Match(line, @"(?[^,]+), Ln (?[0-9]+), Col (?[0-9]+)"); + var mErr = Regex.Match(line, @"(?[^,]+), Ln (?[0-9]+), Col (?[0-9]+)"); if (mErr.Success) { - string filename = mErr.Groups["file"].Value; + var filename = mErr.Groups["file"].Value; try { if (File.Exists(filename)) @@ -493,7 +461,7 @@ private void ascRunner_Error(object sender, string line) } } catch {} - errorDesc = String.Format("{0}:{1}: col: {2}: {3}", filename, mErr.Groups["line"].Value, mErr.Groups["col"].Value, errorDesc); + errorDesc = $"{filename}:{mErr.Groups["line"].Value}: col: {mErr.Groups["col"].Value}: {errorDesc}"; ascRunner_OutputError(sender, errorDesc); } errorState++; @@ -504,10 +472,10 @@ private void ascRunner_Error(object sender, string line) } else if (line.Trim().Length > 0) ascRunner_OutputError(sender, line); } - - private void ascRunner_OutputError(object sender, string line) + + void ascRunner_OutputError(object sender, string line) { - if (line == null) return; + if (line is null) return; PluginBase.RunAsync(delegate { if (line.StartsWithOrdinal("Exception ")) @@ -517,22 +485,20 @@ private void ascRunner_OutputError(object sender, string line) } if (silentChecking) { - if (SyntaxError != null) SyntaxError(line); + SyntaxError?.Invoke(line); return; } TraceManager.Add(line, -3); - if (!notificationSent) - { - notificationSent = true; - TraceManager.Add("Done(1)", -2); - EventManager.DispatchEvent(this, new TextEvent(EventType.ProcessEnd, "Done(1)")); - ASContext.SetStatusText(TextHelper.GetString("Info.AscDone")); - EventManager.DispatchEvent(this, new DataEvent(EventType.Command, "ResultsPanel.ShowResults", null)); - } + if (notificationSent) return; + notificationSent = true; + TraceManager.Add("Done(1)", -2); + EventManager.DispatchEvent(this, new TextEvent(EventType.ProcessEnd, "Done(1)")); + ASContext.SetStatusText(TextHelper.GetString("Info.AscDone")); + EventManager.DispatchEvent(this, new DataEvent(EventType.Command, "ResultsPanel.ShowResults", null)); }); } - private void ascRunner_Output(object sender, string line) + void ascRunner_Output(object sender, string line) { if (line.StartsWithOrdinal("(ash)")) { @@ -551,17 +517,17 @@ private void ascRunner_Output(object sender, string line) if (!silentChecking) TraceManager.AddAsync(line, 0); } - private void ascRunner_End() + static void ascRunner_End() { TraceManager.AddAsync("Done(0)", -2); } - - private void mxmlcRunner_Error(object sender, string line) + + static void mxmlcRunner_Error(object sender, string line) { TraceManager.AddAsync(line, -3); } - private void mxmlcRunner_Output(object sender, string line) + void mxmlcRunner_Output(object sender, string line) { PluginBase.RunAsync(delegate { @@ -581,10 +547,10 @@ private void mxmlcRunner_Output(object sender, string line) else TraceManager.Add(line, 0); }); } - - private void RunAfterBuild() + + void RunAfterBuild() { - if (builtSWF == null || !File.Exists(builtSWF)) + if (!File.Exists(builtSWF)) { debugMode = false; return; diff --git a/External/Plugins/AS3Context/Completion/CodeComplete.cs b/External/Plugins/AS3Context/Completion/CodeComplete.cs new file mode 100644 index 0000000000..af864d440f --- /dev/null +++ b/External/Plugins/AS3Context/Completion/CodeComplete.cs @@ -0,0 +1,176 @@ +using System.Collections.Generic; +using System.Linq; +using ASCompletion.Completion; +using ASCompletion.Context; +using ASCompletion.Model; +using PluginCore; +using ScintillaNet; + +namespace AS3Context.Completion +{ + class CodeComplete : ASComplete + { + /// + protected override ASResult EvalExpression(string expression, ASExpr context, FileModel inFile, ClassModel inClass, bool complete, bool asFunction, bool filterVisibility) + { + if (!string.IsNullOrEmpty(expression)) + { + var ctx = ASContext.Context; + var features = ctx.Features; + // for example: 1.0., 5e-324. + if (char.IsDigit(expression, 0) + // for example: -1. + || (expression.Length > 1 && expression[0] == '-' && char.IsDigit(expression, 1)) + // for example: --1. + || (expression.Length > 2 && expression[0] == '-' && expression[1] == '-' && + char.IsDigit(expression, 2))) + { + int p; + var pe2 = -1; + if (expression.Contains("e-", out var pe1) || expression.Contains("e+", out pe2)) + { + p = expression.IndexOf('.'); + if (p == -1) p = expression.Length - 1; + else if (p < pe1 || p < pe2) + { + var p2 = expression.IndexOf('.', p + 1); + p = p2 != -1 ? p2 : expression.Length - 1; + } + } + else + { + p = expression.IndexOf('.'); + if (p == expression.Length - 1) p = -1; + else if (p != -1) + { + // for example: 1.0. + if (char.IsDigit(expression[p + 1])) + { + var p2 = expression.IndexOf('.', p + 1); + p = p2 != -1 ? p2 : expression.Length - 1; + } + // for example: -1.valueOf(). + else p = -1; + } + } + + if (p != -1) + { + expression = "Number.#." + expression.Substring(p + 1); + return base.EvalExpression(expression, context, inFile, inClass, complete, asFunction, + filterVisibility); + } + } + + if (context.SubExpressions != null) + { + var count = context.SubExpressions.Count - 1; + // transform #2~.#1~.#0~ to #2~.[].[] + for (var i = 0; i <= count; i++) + { + var subExpression = context.SubExpressions[i]; + if (subExpression.Length < 2 || subExpression[0] != '[') continue; + // for example: []. + if (expression[0] == '#' && i == count) + { + var type = ResolveType(features.arrayKey, inFile); + if (type.IsVoid()) break; + expression = type.Name + ".#" + expression.Substring(("#" + i + "~").Length); + context.SubExpressions.RemoveAt(i); + return base.EvalExpression(expression, context, inFile, inClass, complete, asFunction, + filterVisibility); + } + + expression = expression.Replace(">.#" + i + "~", ">" + subExpression); + expression = expression.Replace(".#" + i + "~", "." + subExpression); + } + } + + if (expression.Length > 1 && expression[0] is { } c && (c == '"' || c == '\'')) + { + var type = ResolveType(features.stringKey, inFile); + // for example: ""|, ''| + if (context.SubExpressions is null) expression = type.Name + ".#."; + // for example: ""., ''. + else + { + var pattern = c + ".#" + (context.SubExpressions.Count - 1) + "~"; + var startIndex = expression.IndexOfOrdinal(pattern) + pattern.Length; + expression = type.Name + ".#" + expression.Substring(startIndex); + } + } + // for example: new []. + else if (expression.Contains(">.[")) expression = expression.Replace(">.[", ">["); + // transform Vector. to Vector + else if (expression.Contains(".<")) expression = expression.Replace(".<", "<"); + // for example: /pattern/. + else if (expression.StartsWithOrdinal("#RegExp")) expression = expression.Substring(1); + else if (!context.SubExpressions.IsNullOrEmpty()) + { + var expr = context.SubExpressions.Last(); + // for example: (v as T)., (v is Complete)., ... + if (expr.Length >= 8 /*"(v as T)".Length*/ && expr[0] == '(') + { + var type = ctx.ResolveToken(expr, inFile); + if (!type.IsVoid()) + { + expression = type.Name + ".#" + + expression.Substring(("#" + (context.SubExpressions.Count - 1) + "~").Length); + context.SubExpressions.RemoveAt(context.SubExpressions.Count - 1); + if (context.SubExpressions.Count == 0) context.SubExpressions = null; + } + } + } + } + + return base.EvalExpression(expression, context, inFile, inClass, complete, asFunction, filterVisibility); + } + + /// + protected override bool HandleNewCompletion(ScintillaControl sci, string tail, bool autoHide, string keyword, List list) + { + if (keyword == "new") list.RemoveAll(it => it is MemberItem {Member: { } member} && (member.Flags & FlagType.Interface) != 0); + return base.HandleNewCompletion(sci, tail, autoHide, keyword, list); + } + + /// + protected override bool IsAvailableForToolTip(ScintillaControl sci, int position) + { + return base.IsAvailableForToolTip(sci, position) + || (sci.GetWordFromPosition(position) is { } word + && (word == "as" || word == "is" || word == "instanceof" || word == "typeof" || word == "delete")); + } + + /// + protected override string GetToolTipTextEx(ASResult expr) + { + if (expr.Member is null && expr.Context?.Value is {} s) + { + switch (s) + { + // for example: variable as$(EntryPoint) Type + case "as": + expr.Member = Context.StubAsExpression; + break; + // for example: variable is$(EntryPoint) Type + case "is": + expr.Member = Context.StubIsExpression; + break; + // for example: variable instanceof$(EntryPoint) function + case "instanceof": + expr.Member = Context.StubInstanceOfExpression; + break; + // for example: typeof(EntryPoint) expression + case "typeof": + expr.Member = Context.StubTypeOfExpression; + break; + // for example: delete$(EntryPoint) reference + case "delete": + expr.Member = Context.StubDeleteExpression; + break; + } + } + return base.GetToolTipTextEx(expr); + } + } +} \ No newline at end of file diff --git a/External/Plugins/AS3Context/Context.cs b/External/Plugins/AS3Context/Context.cs index 190ffc3258..46ea4ca287 100644 --- a/External/Plugins/AS3Context/Context.cs +++ b/External/Plugins/AS3Context/Context.cs @@ -17,29 +17,129 @@ using ScintillaNet.Enums; using SwfOp; using Timer = System.Timers.Timer; -using System.Linq; - +using AS3Context.Completion; + namespace AS3Context { public class Context : AS2Context.Context { - static readonly protected Regex re_genericType = + protected static readonly Regex re_genericType = new Regex("(?[^<]+)\\.<(?.+)>$", RegexOptions.Compiled | RegexOptions.IgnoreCase); // C:\path\to\Main.as$raw$:31: col: 1: Error #1084: Syntax error: expecting rightbrace before end of program. - static readonly protected Regex re_syntaxError = + protected static readonly Regex re_syntaxError = new Regex("(?.*)\\$raw\\$:(?[0-9]+): col: (?[0-9]+):(?.*)", RegexOptions.Compiled); - static readonly protected Regex re_customAPI = + protected static readonly Regex re_customAPI = new Regex("[/\\\\](playerglobal|airglobal|builtin)\\.swc", RegexOptions.Compiled | RegexOptions.IgnoreCase); + internal static readonly MemberModel StubAsExpression = new MemberModel("as operator", null, FlagType.Declaration, 0) + { + Comments = "\r\t * Usage" + + "\r\t * expression as datatype" + + "\r\t * " + + "\r\t * Language Version: ActionScript 3.0" + + "\r\t * Runtime Versions: Flash Player 9" + + "\r\t * " + + "\r\t * Evaluates whether an expression specified by the first operand is a member of the data type specified by the second operand." + + "\r\t * If the first operand is a member of the data type, the result is the first operand. Otherwise, the result is the value null." + + "\r\t * " + + "\r\t * The expression used for the second operand must evaluate to a data type." + + "\r\t * " + + "\r\t * Operands" + + "\r\t * expression:* The value to check against the data type specified." + + "\r\t * datatype:Class The data type used to evaluate the expression operand. The special * type, which means untyped, cannot be used." + + "\r\t * " + + "\r\t * Result" + + "\r\t * Object The result is expression if expression is a member of the data type specified in datatype. Otherwise, the result is the value null." + }; + + internal static readonly MemberModel StubIsExpression = new MemberModel("is operator", null, FlagType.Declaration, 0) + { + Comments = "\r\t * Usage" + + "\r\t * expression is datatype" + + "\r\t * " + + "\r\t * Language Version: ActionScript 3.0" + + "\r\t * Runtime Versions: Flash Player 9" + + "\r\t * " + + "\r\t * Evaluates whether an object is compatible with a specific data type, class, or interface. Use the is operator instead of the instanceof operator for type comparisons. You can also use the is operator to check whether an object implements an interface." + + "\r\t * " + + "\r\t * Result" + + "\r\t * Boolean A value of true if expression1 is compatible with the data type, class, or interface specified in expression2, and false otherwise." + }; + + internal static readonly MemberModel StubInstanceOfExpression = new MemberModel("instaceof operator", null, FlagType.Declaration, 0) + { + Comments = "\r\t * Usage" + + "\r\t * expression instanceof function" + + "\r\t * " + + "\r\t * Language Version: ActionScript 3.0" + + "\r\t * Runtime Versions: Flash Player 9" + + "\r\t * " + + "\r\t * Evaluates whether an expression's prototype chain includes the prototype object for function. The instanceof operator is included for backward compatibility with ECMAScript edition 3, and may be useful for advanced programmers who choose to use prototype-based inheritance with constructor functions instead of classes." + + "\r\t * " + + "\r\t * To check whether an object is a member of a specific data type, use the is operator." + + "\r\t * " + + "\r\t * When used with classes, the instanceof operator is similar to the is operator because a class's prototype chain includes all of its superclasses. Interfaces, however, are not included on prototype chains, so the instanceof operator always results in false when used with interfaces, whereas the is operator results in true if an object belongs to a class that implements the specified interface." + + "\r\t * " + + "\r\t * Note: The ActionScript is operator is the equivalent of the Java instanceof operator." + + "\r\t * " + + "\r\t * Operands" + + "\r\t * expression:Object The object that contains the prototype chain to evaluate." + + "\r\t * function:Object A function object (or class)." + + "\r\t * " + + "\r\t * Result" + + "\r\t * Boolean Returns true if the prototype chain of expression includes the prototype object for function, and false otherwise." + }; + + internal static readonly MemberModel StubTypeOfExpression = new MemberModel("typeof operator", null, FlagType.Declaration, 0) + { + Comments = "\r\t * Usage" + + "\r\t * typeof expression" + + "\r\t * " + + "\r\t * Language Version: ActionScript 3.0" + + "\r\t * Runtime Versions: Flash Player 9" + + "\r\t * " + + "\r\t * Evaluates expression and returns a string specifying the expression's data type. The result is limited to six possible string values: boolean, function, number, object, string, and xml. If you apply this operator to an instance of a user-defined class, the result is the string object. The typeof operator is included for backward compatibility. Use the is operator to check type compatibility." + + "\r\t * " + + "\r\t * Operands" + + "\r\t * expression:Object An object to evaluate." + + "\r\t * " + + "\r\t * Result" + + "\r\t * String A string representation of the type of expression. The following table shows the results of the typeof operator on each type of expression." + }; + + internal static readonly MemberModel StubDeleteExpression = new MemberModel("delete operator", null, FlagType.Declaration, 0) + { + Comments = "\r\t * Usage" + + "\r\t * delete reference" + + "\r\t * " + + "\r\t * Language Version: ActionScript 3.0" + + "\r\t * Runtime Versions: Flash Player 9" + + "\r\t * " + + "\r\t * Destroys the object property specified by reference; the result is true if the property does not exist after the operation completes, and false otherwise. The delete operator returns true if it is called on a nonexistent property or a dynamic property not defined in a class." + + "\r\t * " + + "\r\t * The delete operator can fail and return false if the reference parameter cannot be deleted. You cannot delete fixed properties or variables that are declared with the var statement. A fixed property is a variable or method defined in a class definition." + + "\r\t * " + + "\r\t * The delete operator cannot be used to destroy a property of a class, unless that class is a dynamic class added at runtime. Properties of sealed classes cannot be destroyed using delete. Set the property to null instead." + + "\r\t * " + + "\r\t * Note: You cannot delete an object, but you can make an object eligible for garbage collection by removing all references to the object. The most common reference to an object is a variable that points to it. You can remove such a reference by setting the variable to null. The garbage collector removes any object that has no references." + + "\r\t * " + + "\r\t * Operands" + + "\r\t * reference:* The name of the property to eliminate." + + "\r\t * " + + "\r\t * Result" + + "\r\t * Boolean The value true if the deletion succeeded and false if it failed." + }; + #region initialization - private AS3Settings as3settings; - private bool hasAIRSupport; - private bool hasMobileSupport; - private MxmlFilterContext mxmlFilterContext; // extract inlined AS3 ranges & MXML tags - private Timer timerCheck; - private string fileWithSquiggles; + + readonly AS3Settings as3settings; + bool hasAIRSupport; + bool hasMobileSupport; + MxmlFilterContext mxmlFilterContext; // extract inlined AS3 ranges & MXML tags + readonly Timer timerCheck; + string fileWithSquiggles; protected bool mxmlEnabled; /// @@ -85,7 +185,7 @@ public Context(AS3Settings initSettings) features.checkFileName = true; // allowed declarations access modifiers - Visibility all = Visibility.Public | Visibility.Internal | Visibility.Protected | Visibility.Private; + const Visibility all = Visibility.Public | Visibility.Internal | Visibility.Protected | Visibility.Private; features.classModifiers = all; features.varModifiers = all; features.constModifiers = all; @@ -97,26 +197,21 @@ public Context(AS3Settings initSettings) features.methodModifierDefault = Visibility.Internal; // keywords + features.ClassKey = "class"; + features.InterfaceKey = "interface"; + features.PackageKey = "package"; + features.ExtendsKey = "extends"; + features.ImplementsKey = "implements"; features.dot = "."; features.voidKey = "void"; features.objectKey = "Object"; features.booleanKey = "Boolean"; features.numberKey = "Number"; + features.IntegerKey = "int"; features.stringKey = "String"; features.arrayKey = "Array"; features.dynamicKey = "*"; features.importKey = "import"; - features.typesPreKeys = new string[] { "import", "new", "typeof", "is", "as", "extends", "implements" }; - features.codeKeywords = new string[] { - "var", "function", "const", "new", "delete", "typeof", "is", "as", "return", - "break", "continue", "if", "else", "for", "each", "in", "while", "do", "switch", "case", "default", "with", - "null", "true", "false", "try", "catch", "finally", "throw", "use", "namespace" - }; - features.accessKeywords = new string[] { - "native", "dynamic", "final", "public", "private", "protected", "internal", "static", "override" - }; - features.declKeywords = new string[] { "var", "function", "const", "namespace", "get", "set" }; - features.typesKeywords = new string[] { "import", "class", "interface" }; features.varKey = "var"; features.constKey = "const"; features.functionKey = "function"; @@ -131,39 +226,56 @@ public Context(AS3Settings initSettings) features.privateKey = "private"; features.intrinsicKey = "extern"; features.namespaceKey = "namespace"; - features.ArithmeticOperators = new HashSet{'+', '-', '*', '/', '%'}; + features.ThisKey = "this"; + features.BaseKey = "super"; + features.ReturnKey = "return"; + features.typesPreKeys = new[] { features.importKey, "new", "typeof", "instanceof", "is", "as", features.ExtendsKey, features.ImplementsKey }; + features.codeKeywords = new[] { + "var", "function", "const", "new", "delete", "typeof", "is", "as", features.ReturnKey, + "break", "continue", "if", "else", "for", "each", "in", "while", "do", "switch", "case", "default", "with", + "null", "true", "false", "try", "catch", "finally", "throw", "use", "namespace", "instanceof", + }; + features.accessKeywords = new[] {"native", "dynamic", "final", "public", "private", "protected", "internal", "static", "override"}; + features.declKeywords = new[] {features.varKey, features.functionKey, features.constKey, features.namespaceKey, features.getKey, features.setKey}; + features.typesKeywords = new[] {features.importKey, features.ClassKey, features.InterfaceKey}; + features.ArithmeticOperators = new HashSet {'+', '-', '*', '/', '%'}; features.IncrementDecrementOperators = new[] {"++", "--"}; - features.OtherOperators = new HashSet {"delete", "typeof", "new"}; - /* INITIALIZATION */ + features.BitwiseOperators = new[] {"~", "&", "|", "^", "<<", ">>", ">>>"}; + features.BooleanOperators = new[] {"<", ">", "&&", "||", "!=", "==", "!==", "===", "!"}; + features.TernaryOperators = new[] {"?", ":"}; + features.Literals = new HashSet {"int", "uint"}; + features.OperatorKeywords = new HashSet + { + "case", + "in", + "throw", + "typeof", + "delete", + }; settings = initSettings; - //BuildClassPath(); // defered to first use + CodeComplete = new CodeComplete(); // live syntax checking - timerCheck = new Timer(500); - timerCheck.SynchronizingObject = PluginBase.MainForm as Form; - timerCheck.AutoReset = false; - timerCheck.Elapsed += new ElapsedEventHandler(timerCheck_Elapsed); - FlexShells.SyntaxError += new SyntaxErrorHandler(FlexShell_SyntaxError); + timerCheck = new Timer(500) {SynchronizingObject = PluginBase.MainForm as Form, AutoReset = false}; + timerCheck.Elapsed += timerCheck_Elapsed; + FlexShells.SyntaxError += FlexShell_SyntaxError; } #endregion #region classpath management /// - /// Classpathes & classes cache initialisation + /// Classpathes & classes cache initialization /// public override void BuildClassPath() { ReleaseClasspath(); started = true; - if (as3settings == null) throw new Exception("BuildClassPath() must be overridden"); - if (contextSetup == null) + if (as3settings is null) throw new Exception("BuildClassPath() must be overridden"); + contextSetup ??= new ContextSetupInfos { - contextSetup = new ContextSetupInfos(); - contextSetup.Lang = settings.LanguageId; - contextSetup.Platform = "Flash Player"; - contextSetup.Version = as3settings.DefaultFlashVersion; - } + Lang = settings.LanguageId, Platform = "Flash Player", Version = as3settings.DefaultFlashVersion + }; // external version definition platform = contextSetup.Platform; @@ -173,8 +285,9 @@ public override void BuildClassPath() hasAIRSupport = platform == "AIR" || platform == "AIR Mobile"; hasMobileSupport = platform == "AIR Mobile"; - string cpCheck = contextSetup.Classpath != null ? - String.Join(";", contextSetup.Classpath).Replace('\\', '/') : ""; + var cpCheck = contextSetup.Classpath != null + ? string.Join(";", contextSetup.Classpath).Replace('\\', '/') + : ""; // check if CP contains a custom playerglobal.swc bool hasCustomAPI = re_customAPI.IsMatch(cpCheck); @@ -192,11 +305,10 @@ public override void BuildClassPath() : as3settings.GetDefaultSDK().Path; char S = Path.DirectorySeparatorChar; - if (compiler == null) - compiler = Path.Combine(PathHelper.ToolDir, "flexlibs"); + compiler ??= Path.Combine(PathHelper.ToolDir, "flexlibs"); string frameworks = compiler + S + "frameworks"; string sdkLibs = frameworks + S + "libs"; - string sdkLocales = frameworks + S + "locale" + S + PluginBase.MainForm.Settings.LocaleVersion; + string sdkLocales = frameworks + S + "locale" + S + PluginBase.Settings.LocaleVersion; string fallbackLibs = PathHelper.ResolvePath(PathHelper.ToolDir + S + "flexlibs" + S + "frameworks" + S + "libs"); string fallbackLocale = PathHelper.ResolvePath(PathHelper.ToolDir + S + "flexlibs" + S + "frameworks" + S + "locale" + S + "en_US"); List addLibs = new List(); @@ -207,7 +319,7 @@ public override void BuildClassPath() sdkLibs = PathHelper.ResolvePath(PathHelper.ToolDir + S + "flexlibs" + S + "frameworks" + S + "libs" + S + "player"); } - if (majorVersion > 0 && !String.IsNullOrEmpty(sdkLibs) && Directory.Exists(sdkLibs)) + if (majorVersion > 0 && Directory.Exists(sdkLibs)) { // core API SWC if (!hasCustomAPI) @@ -219,16 +331,16 @@ public override void BuildClassPath() } else { - bool swcPresent = false; - string playerglobal = MatchPlayerGlobalExact(majorVersion, minorVersion, sdkLibs); + var swcPresent = false; + var playerglobal = MatchPlayerGlobalExact(majorVersion, minorVersion, sdkLibs); if (playerglobal != null) swcPresent = true; else playerglobal = MatchPlayerGlobalExact(majorVersion, minorVersion, fallbackLibs); - if (playerglobal == null) playerglobal = MatchPlayerGlobalAny(ref majorVersion, ref minorVersion, fallbackLibs); - if (playerglobal == null) playerglobal = MatchPlayerGlobalAny(ref majorVersion, ref minorVersion, sdkLibs); + playerglobal ??= MatchPlayerGlobalAny(ref majorVersion, ref minorVersion, fallbackLibs) + ?? MatchPlayerGlobalAny(ref majorVersion, ref minorVersion, sdkLibs); if (playerglobal != null) { // add missing SWC in new SDKs - if (!swcPresent && sdkLibs.IndexOfOrdinal(S + "flexlibs") < 0 && Directory.Exists(compiler)) + if (!swcPresent && !sdkLibs.Contains(S + "flexlibs") && Directory.Exists(compiler)) { string swcDir = sdkLibs + S + "player" + S; if (!Directory.Exists(swcDir + "9") && !Directory.Exists(swcDir + "10")) @@ -262,35 +374,35 @@ public override void BuildClassPath() // Flex framework if (cpCheck.IndexOf("Library/AS3/frameworks/Flex", StringComparison.OrdinalIgnoreCase) >= 0) - { - bool isFlexJS = cpCheck.IndexOf("Library/AS3/frameworks/FlexJS", StringComparison.OrdinalIgnoreCase) >= 0; - - if (!isFlexJS) - { - addLibs.Add("framework.swc"); - addLibs.Add("mx/mx.swc"); - addLibs.Add("rpc.swc"); - addLibs.Add("datavisualization.swc"); - addLibs.Add("flash-integration.swc"); - addLocales.Add("framework_rb.swc"); - addLocales.Add("mx_rb.swc"); - addLocales.Add("rpc_rb.swc"); - addLocales.Add("datavisualization_rb.swc"); - addLocales.Add("flash-integration_rb.swc"); + { + bool isFlexJS = cpCheck.IndexOf("Library/AS3/frameworks/FlexJS", StringComparison.OrdinalIgnoreCase) >= 0; + + if (!isFlexJS) + { + addLibs.Add("framework.swc"); + addLibs.Add("mx/mx.swc"); + addLibs.Add("rpc.swc"); + addLibs.Add("datavisualization.swc"); + addLibs.Add("flash-integration.swc"); + addLocales.Add("framework_rb.swc"); + addLocales.Add("mx_rb.swc"); + addLocales.Add("rpc_rb.swc"); + addLocales.Add("datavisualization_rb.swc"); + addLocales.Add("flash-integration_rb.swc"); } if (hasAIRSupport) { addLibs.Add("air" + S + "airframework.swc"); addLocales.Add("airframework_rb.swc"); - } - - if (isFlexJS) - { - string flexJsLibs = frameworks + S + "as" + S + "libs"; - addLibs.Add(flexJsLibs + S + "FlexJSUI.swc"); - //addLibs.Add(flexJsLibs + S + "FlexJSJX.swc"); - MxmlFilter.AddManifest("http://ns.adobe.com/mxml/2009", as3Fmk + S + "FlexJS" + S + "manifest.xml"); + } + + if (isFlexJS) + { + string flexJsLibs = frameworks + S + "as" + S + "libs"; + addLibs.Add(flexJsLibs + S + "FlexJSUI.swc"); + //addLibs.Add(flexJsLibs + S + "FlexJSJX.swc"); + MxmlFilter.AddManifest("http://ns.adobe.com/mxml/2009", as3Fmk + S + "FlexJS" + S + "manifest.xml"); } else if (cpCheck.IndexOf("Library/AS3/frameworks/Flex4", StringComparison.OrdinalIgnoreCase) >= 0) { @@ -338,10 +450,10 @@ public override void BuildClassPath() // intrinsics (deprecated, excepted for FP10 Vector.) // add from the highest version number (FP11 > FP10 > FP9) - string fp = as3settings.AS3ClassPath + S + "FP"; - for (int i = majorVersion; i >= 9; i--) - { - AddPath(PathHelper.ResolvePath(fp + i)); + string fp = as3settings.AS3ClassPath + S + "FP"; + for (int i = majorVersion; i >= 9; i--) + { + AddPath(PathHelper.ResolvePath(fp + i)); } // add external paths @@ -356,7 +468,7 @@ public override void BuildClassPath() // add library AddPath(PathHelper.LibraryDir + S + "AS3" + S + "classes"); // add user paths from settings - if (settings.UserClasspath != null && settings.UserClasspath.Length > 0) + if (!settings.UserClasspath.IsNullOrEmpty()) { foreach (string cpath in settings.UserClasspath) AddPath(cpath.Trim()); } @@ -381,7 +493,7 @@ public override void BuildClassPath() /// /// Find any playerglobal.swc /// - private string MatchPlayerGlobalAny(ref int majorVersion, ref int minorVersion, string sdkLibs) + string MatchPlayerGlobalAny(ref int majorVersion, ref int minorVersion, string sdkLibs) { char S = Path.DirectorySeparatorChar; string libPlayer = sdkLibs + S + "player"; @@ -398,7 +510,7 @@ private string MatchPlayerGlobalAny(ref int majorVersion, ref int minorVersion, if (Directory.Exists(libPlayer + S + majorVersion)) playerglobal = "player" + S + majorVersion + S + "playerglobal.swc"; - if (playerglobal == null && majorVersion > 9) + if (playerglobal is null && majorVersion > 9) { int tempMajor = majorVersion - 1; int tempMinor = 9; @@ -417,7 +529,7 @@ private string MatchPlayerGlobalAny(ref int majorVersion, ref int minorVersion, /// /// Find version-matching playerglobal.swc /// - private string MatchPlayerGlobalExact(int majorVersion, int minorVersion, string sdkLibs) + string MatchPlayerGlobalExact(int majorVersion, int minorVersion, string sdkLibs) { string playerglobal = null; char S = Path.DirectorySeparatorChar; @@ -434,25 +546,22 @@ private string MatchPlayerGlobalExact(int majorVersion, int minorVersion, string /// public override string[] GetExplorerMask() { - string[] mask = as3settings.AS3FileTypes; - if (mask == null || mask.Length == 0 || (mask.Length == 1 && mask[0] == "")) + var mask = as3settings.AS3FileTypes; + if (mask.IsNullOrEmpty() || (mask.Length == 1 && mask[0] == "")) { - as3settings.AS3FileTypes = mask = new string[] { "*.as", "*.mxml" }; + as3settings.AS3FileTypes = mask = new[] { "*.as", "*.mxml" }; return mask; } - else + var patterns = new List(); + foreach (var it in mask) { - List patterns = new List(); - for (int i = 0; i < mask.Length; i++) - { - string m = mask[i]; - if (string.IsNullOrEmpty(m)) continue; - if (m[1] != '.' && m[0] != '.') m = '.' + m; - if (m[0] != '*') m = '*' + m; - patterns.Add(m); - } - return patterns.ToArray(); + string m = it; + if (string.IsNullOrEmpty(m)) continue; + if (m[1] != '.' && m[0] != '.') m = '.' + m; + if (m[0] != '*') m = '*' + m; + patterns.Add(m); } + return patterns.ToArray(); } /// @@ -505,30 +614,29 @@ public override void ExploreVirtualPath(PathModel path) public override void RemoveClassCompilerCache() { // not implemented - is there any? - } - - /// - /// Create a new file model without parsing file - /// - /// Full path - /// File model - public override FileModel CreateFileModel(string fileName) - { - if (string.IsNullOrEmpty(fileName) || !File.Exists(fileName)) - return new FileModel(fileName); - - fileName = PathHelper.GetLongPathName(fileName); - if (mxmlEnabled && fileName.EndsWith(".mxml", StringComparison.OrdinalIgnoreCase)) - { - FileModel nFile = new FileModel(fileName); - nFile.Context = this; - nFile.HasFiltering = true; - return nFile; - } - else return base.CreateFileModel(fileName); } - private void GuessPackage(string fileName, FileModel nFile) + /// + /// Create a new file model without parsing file + /// + /// Full path + /// File model + public override FileModel CreateFileModel(string fileName) + { + if (!File.Exists(fileName)) return new FileModel(fileName); + fileName = PathHelper.GetLongPathName(fileName); + if (mxmlEnabled && fileName.EndsWith(".mxml", StringComparison.OrdinalIgnoreCase)) + { + FileModel nFile = new FileModel(fileName); + nFile.Context = this; + nFile.HasFiltering = true; + return nFile; + } + + return base.CreateFileModel(fileName); + } + + void GuessPackage(string fileName, FileModel nFile) { foreach(PathModel aPath in classPath) if (fileName.StartsWith(aPath.Path, StringComparison.OrdinalIgnoreCase)) @@ -541,15 +649,6 @@ private void GuessPackage(string fileName, FileModel nFile) } } - /// - /// Build the file DOM - /// - /// File path - protected override void GetCurrentFileModel(string fileName) - { - base.GetCurrentFileModel(fileName); - } - /// /// Refresh the file model /// @@ -568,16 +667,6 @@ public override void UpdateCurrentFile(bool updateUI) } } - /// - /// Update the class/member context for the given line number. - /// Be carefull to restore the context after calling it with a custom line number - /// - /// - public override void UpdateContext(int line) - { - base.UpdateContext(line); - } - /// /// Called if a FileModel needs filtering /// - define inline AS3 ranges @@ -608,8 +697,9 @@ public override void FilterSource(FileModel model) internal void OnFileOperation(NotifyEvent e) { timerCheck.Stop(); - foreach (ITabbedDocument doc in PluginBase.MainForm.Documents) - if (doc.FileName == fileWithSquiggles) ClearSquiggles(doc.SciControl); + foreach (var doc in PluginBase.MainForm.Documents) + if (doc.SciControl is { } sci && sci.FileName == fileWithSquiggles) + ClearSquiggles(sci); } public override void TrackTextChange(ScintillaControl sender, int position, int length, int linesAdded) @@ -622,42 +712,38 @@ public override void TrackTextChange(ScintillaControl sender, int position, int } } - private void timerCheck_Elapsed(object sender, ElapsedEventArgs e) - { - BackgroundSyntaxCheck(); - } + void timerCheck_Elapsed(object sender, ElapsedEventArgs e) => BackgroundSyntaxCheck(); /// /// Checking syntax of current file /// - private void BackgroundSyntaxCheck() + void BackgroundSyntaxCheck() { if (!IsFileValid) return; - ScintillaControl sci = CurSciControl; - if (sci == null) return; + var sci = PluginBase.MainForm.CurrentDocument?.SciControl; + if (sci is null) return; ClearSquiggles(sci); - string src = CurSciControl.Text; - string sdk = PluginBase.CurrentProject != null && PluginBase.CurrentProject.Language == "as3" + var sdk = PluginBase.CurrentProject != null && PluginBase.CurrentProject.Language == "as3" ? PluginBase.CurrentProject.CurrentSDK : as3settings.GetDefaultSDK().Path; - FlexShells.Instance.CheckAS3(CurrentFile, sdk, src); - } - - private void AddSquiggles(ScintillaControl sci, int line, int start, int end) - { - if (sci == null) return; - fileWithSquiggles = CurrentFile; - int position = sci.PositionFromLine(line) + start; - sci.AddHighlight(2, (int)IndicatorStyle.Squiggle, 0x000000ff, position, end - start); + FlexShells.Instance.CheckAS3(CurrentFile, sdk, sci.Text); + } + + void AddSquiggles(ScintillaControl sci, int line, int start, int end) + { + if (sci is null) return; + fileWithSquiggles = CurrentFile; + int position = sci.PositionFromLine(line) + start; + sci.AddHighlight(2, (int)IndicatorStyle.Squiggle, 0x000000ff, position, end - start); } - private void ClearSquiggles(ScintillaControl sci) + void ClearSquiggles(ScintillaControl sci) { - if (sci == null) return; + if (sci is null) return; try - { + { sci.RemoveHighlights(2); } finally @@ -666,26 +752,25 @@ private void ClearSquiggles(ScintillaControl sci) } } - private void FlexShell_SyntaxError(string error) + void FlexShell_SyntaxError(string error) { if (!IsFileValid) return; - Match m = re_syntaxError.Match(error); + var document = PluginBase.MainForm.CurrentDocument; + if (document is null || !document.IsEditable) return; + var m = re_syntaxError.Match(error); if (!m.Success) return; - ITabbedDocument document = PluginBase.MainForm.CurrentDocument; - if (document == null || !document.IsEditable) return; - - ScintillaControl sci = document.SplitSci1; - ScintillaControl sci2 = document.SplitSci2; + var sci1 = document.SplitSci1; + var sci2 = document.SplitSci2; if (m.Groups["filename"].Value != CurrentFile) return; try { int line = int.Parse(m.Groups["line"].Value) - 1; - if (sci.LineCount < line) return; - int start = MBSafeColumn(sci, line, int.Parse(m.Groups["col"].Value) - 1); - if (line == sci.LineCount && start == 0 && line > 0) start = -1; - AddSquiggles(sci, line, start, start + 1); + if (sci1.LineCount < line) return; + int start = MBSafeColumn(sci1, line, int.Parse(m.Groups["col"].Value) - 1); + if (line == sci1.LineCount && start == 0 && line > 0) start = -1; + AddSquiggles(sci1, line, start, start + 1); AddSquiggles(sci2, line, start, start + 1); } catch { } @@ -694,9 +779,9 @@ private void FlexShell_SyntaxError(string error) /// /// Convert multibyte column to byte length /// - private int MBSafeColumn(ScintillaControl sci, int line, int length) + static int MBSafeColumn(ScintillaControl sci, int line, int length) { - String text = sci.GetLine(line) ?? ""; + var text = sci.GetLine(line) ?? ""; length = Math.Min(length, text.Length); return sci.MBSafeTextLength(text.Substring(0, length)); } @@ -713,27 +798,27 @@ private int MBSafeColumn(ScintillaControl sci, int line, int length) /// Completion visibility public override Visibility TypesAffinity(ClassModel inClass, ClassModel withClass) { - if (inClass == null || withClass == null) return Visibility.Public; + if (inClass is null || withClass is null) return Visibility.Public; // same file if (inClass.InFile == withClass.InFile) return Visibility.Public | Visibility.Internal | Visibility.Protected | Visibility.Private; // same package - Visibility acc = Visibility.Public; - if (inClass.InFile.Package == withClass.InFile.Package) acc |= Visibility.Internal; + var result = Visibility.Public; + if (inClass.InFile.Package == withClass.InFile.Package) result |= Visibility.Internal; // inheritance affinity - ClassModel tmp = inClass; + var tmp = inClass; while (!tmp.IsVoid()) { if (tmp.Type == withClass.Type) { - acc |= Visibility.Protected; + result |= Visibility.Protected; break; } tmp = tmp.Extends; } - return acc; + return result; } /// @@ -746,49 +831,49 @@ public override MemberList GetAllProjectClasses() if (!completionCache.IsDirty && completionCache.AllTypes != null) return completionCache.AllTypes; - MemberList fullList = new MemberList(); + var fullList = new MemberList(); ClassModel aClass; MemberModel item; // public & internal classes string package = CurrentModel?.Package; - foreach (PathModel aPath in classPath) if (aPath.IsValid && !aPath.Updating) - { - aPath.ForeachFile((aFile) => + foreach (var aPath in classPath) + if (aPath.IsValid && !aPath.Updating) { - if (!aFile.HasPackage) - return true; // skip - - aClass = aFile.GetPublicClass(); - if (!aClass.IsVoid() && aClass.IndexType == null) + aPath.ForeachFile((aFile) => { - if (aClass.Access == Visibility.Public - || (aClass.Access == Visibility.Internal && aFile.Package == package)) + if (!aFile.HasPackage) + return true; // skip + + aClass = aFile.GetPublicClass(); + if (!aClass.IsVoid() && aClass.IndexType is null) { - item = aClass.ToMemberModel(); - item.Name = item.Type; - fullList.Add(item); + if (aClass.Access == Visibility.Public + || (aClass.Access == Visibility.Internal && aFile.Package == package)) + { + item = aClass.ToMemberModel(); + item.Name = item.Type; + fullList.Add(item); + } } - } - if (aFile.Package.Length > 0 && aFile.Members.Count > 0) - { - foreach (MemberModel member in aFile.Members) + if (aFile.Package.Length > 0 && aFile.Members.Count > 0) { - item = member.Clone() as MemberModel; - item.Name = aFile.Package + "." + item.Name; - fullList.Add(item); + foreach (var member in aFile.Members) + { + item = member.Clone(); + item.Name = aFile.Package + "." + item.Name; + fullList.Add(item); + } } - } - else if (aFile.Members.Count > 0) - { - foreach (MemberModel member in aFile.Members) + else if (aFile.Members.Count > 0) { - item = member.Clone() as MemberModel; - fullList.Add(item); + foreach (var member in aFile.Members) + { + fullList.Add(member.Clone()); + } } - } - return true; - }); - } + return true; + }); + } // void fullList.Add(new MemberModel(features.voidKey, features.voidKey, FlagType.Class | FlagType.Intrinsic, 0)); // private classes @@ -802,56 +887,41 @@ public override MemberList GetAllProjectClasses() public override bool OnCompletionInsert(ScintillaControl sci, int position, string text, char trigger) { - if (text == "Vector") + if (text != "Vector") return text.StartsWithOrdinal("Vector.<"); + string insert = null; + var line = sci.GetLine(sci.LineFromPosition(position)); + var m = Regex.Match(line, @"\s*=\s*new"); + if (m.Success) { - string insert = null; - string line = sci.GetLine(sci.LineFromPosition(position)); - Match m = Regex.Match(line, @"\svar\s+(?.+)\s*:\s*Vector\.<(?.+)(?=(>\s*=))"); - if (m.Success) - { - insert = String.Format(".<{0}>", m.Groups["indextype"].Value); - } - else - { - m = Regex.Match(line, @"\s*=\s*new"); - if (m.Success) - { - ASResult result = ASComplete.GetExpressionType(sci, sci.PositionFromLine(sci.LineFromPosition(position)) + m.Index); - if (result != null && !result.IsNull() && result.Member != null && result.Member.Type != null) - { - m = Regex.Match(result.Member.Type, @"(?<=<).+(?=>)"); - if (m.Success) - { - insert = String.Format(".<{0}>", m.Value); - } - } - } - if (insert == null) - { - if (trigger == '.' || trigger == '(') return true; - insert = ".<>"; - sci.InsertText(position + text.Length, insert); - sci.CurrentPos = position + text.Length + 2; - sci.SetSel(sci.CurrentPos, sci.CurrentPos); - ASComplete.HandleAllClassesCompletion(sci, "", false, true); - return true; - } - } - if (trigger == '.') - { - sci.InsertText(position + text.Length, insert.Substring(1)); - sci.CurrentPos = position + text.Length; - } - else + var result = ASComplete.GetExpressionType(sci, sci.PositionFromLine(sci.LineFromPosition(position)) + m.Index); + if (result != null && !result.IsNull() && result.Member?.Type != null) { - sci.InsertText(position + text.Length, insert); - sci.CurrentPos = position + text.Length + insert.Length; + m = Regex.Match(result.Member.Type, @"(?<=<).+(?=>)"); + if (m.Success) insert = $".<{m.Value}>"; } + } + if (insert is null) + { + if (trigger == '.' || trigger == '(') return true; + insert = ".<>"; + sci.InsertText(position + text.Length, insert); + sci.CurrentPos = position + text.Length + 2; sci.SetSel(sci.CurrentPos, sci.CurrentPos); + ASComplete.HandleAllClassesCompletion(sci, "", false, true); return true; } - - return false; + if (trigger == '.') + { + sci.InsertText(position + text.Length, insert.Substring(1)); + sci.CurrentPos = position + text.Length; + } + else + { + sci.InsertText(position + text.Length, insert); + sci.CurrentPos = position + text.Length + insert.Length; + } + sci.SetSel(sci.CurrentPos, sci.CurrentPos); + return true; } /// @@ -864,13 +934,14 @@ public override bool OnCompletionInsert(ScintillaControl sci, int position, stri public override bool IsImported(MemberModel member, int atLine) { if (member == ClassModel.VoidClass) return false; - FileModel cFile = Context.CurrentModel; - // same package is auto-imported - string package = member.Type.Length > member.Name.Length + var package = member.InFile?.Package; + if (string.IsNullOrEmpty(package)) package = null; + package ??= member.Type.Length > member.Name.Length ? member.Type.Substring(0, member.Type.Length - member.Name.Length - 1) - : ""; - if (package == cFile.Package) return true; - return base.IsImported(member, atLine); + : string.Empty; + if (package == "globalClassifier") return true; + // same package is auto-imported + return package == Context.CurrentModel.Package || base.IsImported(member, atLine); } /// @@ -882,51 +953,72 @@ public override bool IsImported(MemberModel member, int atLine) public override ClassModel ResolveType(string cname, FileModel inFile) { // handle generic types - if (cname != null && cname.IndexOf('<') >= 0) + if (!string.IsNullOrEmpty(cname)) { - if (cname.StartsWith('<')) + var index = cname.IndexOf('<'); + if (index != -1) { - //transform [] to Vector. - cname = Regex.Replace(cname, @">\[.*", ">"); - cname = "Vector." + cname; + if (index == 0) + { + // transform [] to Vector. + cname = Regex.Replace(cname, @">\[.*", ">"); + cname = "Vector." + cname; + } + // transform Vector to Vector. + if (cname.Contains("Vector<")) cname = cname.Replace("Vector<", "Vector.<"); + var genType = re_genericType.Match(cname); + return genType.Success + ? ResolveGenericType(genType.Groups["gen"].Value, genType.Groups["type"].Value, inFile) + : ClassModel.VoidClass; } - Match genType = re_genericType.Match(cname); - if (genType.Success) - return ResolveGenericType(genType.Groups["gen"].Value, genType.Groups["type"].Value, inFile); - else return ClassModel.VoidClass; } return base.ResolveType(cname, inFile); } + static readonly Regex re_asExpr = new Regex(@"\((?.+)\s(?as)\s+(?\w+)\)"); + static readonly Regex re_isExpr = new Regex(@"\((?.+)\s(?is)\s+(?\w+)\)"); + public override ClassModel ResolveToken(string token, FileModel inFile) { - if (token?.Length > 0) + var tokenLength = token?.Length ?? 0; + if (tokenLength > 0) { - if (token == "") return ResolveType("XML", inFile); if (token.StartsWithOrdinal("0x")) return ResolveType("uint", inFile); var first = token[0]; + if (first == '<' && tokenLength >= 3 && token[tokenLength - 2] == '/' && token[tokenLength - 1] == '>') return ResolveType("XML", inFile); + if (first == '(' && token[token.Length - 1] == ')') + { + if (re_isExpr.IsMatch(token)) return ResolveType(features.booleanKey, inFile); + var m = re_asExpr.Match(token); + if (m.Success) return ResolveType(m.Groups["rv"].Value.Trim(), inFile); + } if (char.IsLetter(first)) { - var index = token.IndexOfOrdinal(" "); + var index = token.IndexOf(' '); if (index != -1) { var word = token.Substring(0, index); - if (word == "delete") return ResolveType(features.booleanKey, inFile); - if (word == "typeof") return ResolveType(features.stringKey, inFile); - if (word == "new" && token[token.Length - 1] == ')') + if (word == "new") { + var dot = ' '; + var parCount = 0; + for (var i = 0; i < tokenLength; i++) + { + var c = token[i]; + if (c == '(') parCount++; + else if (c == ')') + { + parCount--; + if (parCount == 0) dot = '.'; + } + else if (dot != ' ' && c == dot) return ClassModel.VoidClass; + } token = token.Substring(index + 1); - token = Regex.Replace(token, @"\(.*", string.Empty); + if (token[token.Length - 1] == ')') token = Regex.Replace(token, @"\(.*", string.Empty); return ResolveType(token, inFile); } } } - else if (first == '(' && token.Length >= 8/*"(v as T)".Length*/) - { - var m = Regex.Match(token, @"\((?.+)\s(?as)\s+(?\w+)\)"); - if (m.Success) return ResolveType(m.Groups["rv"].Value.Trim(), inFile); - if (Regex.IsMatch(token, @"\((?.+)\s(?is)\s+(?\w+)\)")) return ResolveType(features.booleanKey, inFile); - } } return base.ResolveToken(token, inFile); } @@ -934,43 +1026,49 @@ public override ClassModel ResolveToken(string token, FileModel inFile) /// /// Retrieve/build typed copies of generic types /// - private ClassModel ResolveGenericType(string baseType, string indexType, FileModel inFile) + ClassModel ResolveGenericType(string baseType, string indexType, FileModel inFile) { - ClassModel originalClass = base.ResolveType(baseType, inFile); + var originalClass = base.ResolveType(baseType, inFile); if (originalClass.IsVoid()) return originalClass; + if (indexType == "*") + { + originalClass.IndexType = "*"; + return originalClass; + } - ClassModel indexClass = ResolveType(indexType, inFile); + var indexClass = ResolveType(indexType, inFile); if (indexClass.IsVoid()) return originalClass; indexType = indexClass.QualifiedName; FileModel aFile = originalClass.InFile; // is the type already cloned? - foreach (ClassModel otherClass in aFile.Classes) + foreach (var otherClass in aFile.Classes) if (otherClass.IndexType == indexType) return otherClass; // clone the type - ClassModel aClass = originalClass.Clone() as ClassModel; - + var aClass = originalClass.Clone(); aClass.Name = baseType + ".<" + indexType + ">"; aClass.IndexType = indexType; string typed = "<" + indexType + ">"; - foreach (MemberModel member in aClass.Members) + foreach (var member in aClass.Members) { if (member.Name == baseType) member.Name = baseType.Replace("", typed); - if (member.Type != null && member.Type.IndexOf('T') >= 0) + if (member.Type != null && member.Type.Contains('T')) { - if (member.Type == "T") member.Type = indexType; - else member.Type = member.Type.Replace("", typed); + member.Type = member.Type == "T" + ? indexType + : member.Type.Replace("", typed); } if (member.Parameters != null) { - foreach (MemberModel param in member.Parameters) + foreach (var param in member.Parameters) { - if (param.Type != null && param.Type.IndexOf('T') >= 0) + if (param.Type != null && param.Type.Contains('T')) { - if (param.Type == "T") param.Type = indexType; - else param.Type = param.Type.Replace("", typed); + param.Type = param.Type == "T" + ? indexType + : param.Type.Replace("", typed); } } } @@ -982,20 +1080,20 @@ private ClassModel ResolveGenericType(string baseType, string indexType, FileMod protected MemberList GetPrivateClasses() { - MemberList list = new MemberList(); + var list = new MemberList(); // private classes - if (cFile != null) - foreach (ClassModel model in cFile.Classes) + if (cFile != null) + foreach (var model in cFile.Classes) if (model.Access == Visibility.Private) { - MemberModel item = model.ToMemberModel(); + var item = model.ToMemberModel(); item.Type = item.Name; item.Access = Visibility.Private; list.Add(item); } // 'Class' members if (cClass != null) - foreach (MemberModel member in cClass.Members) + foreach (var member in cClass.Members) if (member.Type == "Class") list.Add(member); return list; } @@ -1005,15 +1103,11 @@ protected MemberList GetPrivateClasses() /// protected override void InitTopLevelElements() { - string filename = "toplevel.as"; + const string filename = "toplevel.as"; topLevel = new FileModel(filename); - - if (topLevel.Members.Search("this", 0, 0) == null) - topLevel.Members.Add(new MemberModel("this", "", FlagType.Variable | FlagType.Intrinsic, Visibility.Public)); - if (topLevel.Members.Search("super", 0, 0) == null) - topLevel.Members.Add(new MemberModel("super", "", FlagType.Variable | FlagType.Intrinsic, Visibility.Public)); - if (topLevel.Members.Search(features.voidKey, 0, 0) == null) - topLevel.Members.Add(new MemberModel(features.voidKey, "", FlagType.Intrinsic, Visibility.Public)); + if (!topLevel.Members.Contains(features.ThisKey)) topLevel.Members.Add(new MemberModel(features.ThisKey, string.Empty, FlagType.Variable | FlagType.Intrinsic, Visibility.Public)); + if (!topLevel.Members.Contains(features.BaseKey)) topLevel.Members.Add(new MemberModel(features.BaseKey, string.Empty, FlagType.Variable | FlagType.Intrinsic, Visibility.Public)); + if (!topLevel.Members.Contains(features.voidKey)) topLevel.Members.Add(new MemberModel(features.voidKey, string.Empty, FlagType.Intrinsic, Visibility.Public)); topLevel.Members.Sort(); } @@ -1021,14 +1115,14 @@ public override string GetDefaultValue(string type) { if (string.IsNullOrEmpty(type) || type == features.voidKey) return null; if (type == features.dynamicKey) return "undefined"; - switch (type) + return type switch { - case "int": - case "uint": return "0"; - case "Number": return "NaN"; - case "Boolean": return "false"; - default: return "null"; - } + "int" => "0", + "uint" => "0", + "Number" => "NaN", + "Boolean" => "false", + _ => "null", + }; } public override IEnumerable DecomposeTypes(IEnumerable types) @@ -1070,25 +1164,19 @@ public override IEnumerable DecomposeTypes(IEnumerable types) /// /// Retrieve the context's default compiler path /// - public override string GetCompilerPath() - { - return as3settings.GetDefaultSDK().Path ?? "Tools\\flexsdk"; - } + public override string GetCompilerPath() => as3settings.GetDefaultSDK().Path ?? "Tools\\flexsdk"; /// /// Check current file's syntax /// public override void CheckSyntax() { - if (IsFileValid && cFile.InlinedIn == null) - { - PluginBase.MainForm.CallCommand("Save", null); - - string sdk = PluginBase.CurrentProject != null - ? PluginBase.CurrentProject.CurrentSDK - : PathHelper.ResolvePath(as3settings.GetDefaultSDK().Path); - FlexShells.Instance.CheckAS3(cFile.FileName, sdk); - } + if (!IsFileValid || cFile.InlinedIn != null) return; + PluginBase.MainForm.CallCommand("Save", null); + var sdk = PluginBase.CurrentProject != null + ? PluginBase.CurrentProject.CurrentSDK + : PathHelper.ResolvePath(as3settings.GetDefaultSDK().Path); + FlexShells.Instance.CheckAS3(cFile.FileName, sdk); } /// @@ -1102,15 +1190,11 @@ public override void RunCMD(string append) MessageBar.ShowWarning(TextHelper.GetString("Info.InvalidClass")); return; } - - string command = (append ?? "") + " -- " + CurrentFile; + var command = (append ?? "") + " -- " + CurrentFile; FlexShells.Instance.RunMxmlc(command, as3settings.GetDefaultSDK().Path); } - private bool IsCompilationTarget() - { - return (!MainForm.CurrentDocument.IsUntitled && CurrentModel.Version >= 3); - } + bool IsCompilationTarget() => (!PluginBase.MainForm.CurrentDocument.IsUntitled && CurrentModel.Version >= 3); /// /// Calls RunCMD with additional parameters taken from the classes @mxmlc doc tag @@ -1122,15 +1206,108 @@ public override bool BuildCMD(bool failSilently) MessageBar.ShowWarning(TextHelper.GetString("Info.InvalidClass")); return false; } - - MainForm.CallCommand("SaveAllModified", null); - - string sdk = PluginBase.CurrentProject != null + PluginBase.MainForm.CallCommand("SaveAllModified", null); + var sdk = PluginBase.CurrentProject != null ? PluginBase.CurrentProject.CurrentSDK : as3settings.GetDefaultSDK().Path; FlexShells.Instance.QuickBuild(CurrentModel, sdk, failSilently, as3settings.PlayAfterBuild); return true; } #endregion + + #region Custom behavior of Scintilla + + /// + public override void OnBraceMatch(ScintillaControl sci) + { + if (!sci.IsBraceMatching || sci.SelTextSize != 0) return; + var position = sci.CurrentPos - 1; + var character = (char) sci.CharAt(position); + if (character != '<' && character != '>') + { + position = sci.CurrentPos; + character = (char) sci.CharAt(position); + } + if (character == '<' || character == '>') + { + if (!sci.PositionIsOnComment(position)) + { + var bracePosStart = position; + var bracePosEnd = BraceMatch(sci, position); + if (bracePosEnd != -1) sci.BraceHighlight(bracePosStart, bracePosEnd); + if (sci.UseHighlightGuides) + { + var line = sci.LineFromPosition(position); + sci.HighlightGuide = sci.GetLineIndentation(line); + } + } + else + { + sci.BraceHighlight(-1, -1); + sci.HighlightGuide = 0; + } + } + } + + /// + /// Find the position of a matching '<' and '>' or INVALID_POSITION if no match. + /// + protected internal int BraceMatch(ScintillaControl sci, int position) + { + if (sci.PositionIsOnComment(position) || sci.PositionIsInString(position)) return -1; + var language = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage); + if (language is null) return -1; + var characters = language.characterclass.Characters; + var sub = 0; + switch (sci.CharAt(position)) + { + case '<': + var length = sci.TextLength; + while (position < length) + { + position++; + if (sci.PositionIsOnComment(position)) continue; + var c = sci.CharAt(position); + if (c == ' ') continue; + if (c == '<') sub++; + else if (c == '>') + { + sub--; + if (sub < 0) return position; + } + else if (c != '.' + // Vector> + && !characters.Contains((char) c)) + { + return -1; + } + } + break; + case '>': + while (position >= 0) + { + position--; + if (sci.PositionIsOnComment(position)) continue; + var c = sci.CharAt(position); + if (c == ' ') continue; + if (c == '>') sub++; + else if (c == '<') + { + sub--; + if (sub < 0) return position; + } + else if (c != '.' + // Vector> + && !characters.Contains((char) c)) + { + return -1; + } + } + break; + } + return -1; + } + + #endregion } -} +} \ No newline at end of file diff --git a/External/Plugins/AS3Context/Controls/ObjectRefsGrid.cs b/External/Plugins/AS3Context/Controls/ObjectRefsGrid.cs index 1dbb5addf7..d834aa5127 100644 --- a/External/Plugins/AS3Context/Controls/ObjectRefsGrid.cs +++ b/External/Plugins/AS3Context/Controls/ObjectRefsGrid.cs @@ -1,5 +1,4 @@ -using System; -using Aga.Controls.Tree; +using Aga.Controls.Tree; using Aga.Controls.Tree.NodeControls; using PluginCore; using PluginCore.Helpers; @@ -9,9 +8,9 @@ namespace AS3Context.Controls { public class ObjectRefsGrid:TreeViewAdv { - NodeTextBox methodTB; - NodeTextBox fileTB; - NodeTextBox lineTB; + readonly NodeTextBox methodTB; + readonly NodeTextBox fileTB; + readonly NodeTextBox lineTB; public ObjectRefsGrid() { @@ -60,10 +59,10 @@ public ObjectRefsGrid() public class ObjectRefsNode : Node { - string method; - string path; - string file; - string line; + readonly string method; + readonly string path; + readonly string file; + readonly string line; public ObjectRefsNode(string method, string file, string line) { @@ -75,22 +74,13 @@ public ObjectRefsNode(string method, string file, string line) this.line = line; } - public String Method - { - get { return method; } - } - public String Path - { - get { return path; } - } - public String File - { - get { return file; } - } - public String Line - { - get { return line; } - } + public string Method => method; + + public string Path => path; + + public string File => file; + + public string Line => line; } public class ObjectRefsModel : TreeModel diff --git a/External/Plugins/AS3Context/Controls/ProfilerLiveObjectsView.cs b/External/Plugins/AS3Context/Controls/ProfilerLiveObjectsView.cs index fae6a7c834..2229fbcfff 100644 --- a/External/Plugins/AS3Context/Controls/ProfilerLiveObjectsView.cs +++ b/External/Plugins/AS3Context/Controls/ProfilerLiveObjectsView.cs @@ -13,72 +13,62 @@ class ProfilerLiveObjectsView { public event ViewObjectEvent OnViewObject; - ListView listView; - private Dictionary items; - private Dictionary finished = new Dictionary(); - private TypeItemComparer comparer; - private ToolStripMenuItem viewObjectsItem; + Dictionary items; + readonly TypeItemComparer comparer; + readonly ToolStripMenuItem viewObjectsItem; - public ListView ListView - { - get { return listView; } - } + public ListView ListView { get; } public ProfilerLiveObjectsView(ListView view) { // config - listView = view; + ListView = view; comparer = new TypeItemComparer(); comparer.SortColumn = TypeItem.COL_COUNT; comparer.Sorting = SortOrder.Descending; - listView.ListViewItemSorter = comparer; - listView.ColumnClick += new ColumnClickEventHandler(listView_ColumnClick); + ListView.ListViewItemSorter = comparer; + ListView.ColumnClick += ListView_ColumnClick; // action viewObjectsItem = new ToolStripMenuItem(TextHelper.GetString("Label.ViewObjectsItem")); - viewObjectsItem.Click += new EventHandler(onViewObjects); + viewObjectsItem.Click += OnViewObjects; - listView.ContextMenuStrip = new ContextMenuStrip(); - listView.ContextMenuStrip.Font = PluginBase.Settings.DefaultFont; - listView.ContextMenuStrip.Renderer = new DockPanelStripRenderer(false); - listView.ContextMenuStrip.Items.Add(viewObjectsItem); + ListView.ContextMenuStrip = new ContextMenuStrip(); + ListView.ContextMenuStrip.Font = PluginBase.Settings.DefaultFont; + ListView.ContextMenuStrip.Renderer = new DockPanelStripRenderer(false); + ListView.ContextMenuStrip.Items.Add(viewObjectsItem); - listView.DoubleClick += new EventHandler(onViewObjects); + ListView.DoubleClick += OnViewObjects; } - void listView_ColumnClick(object sender, ColumnClickEventArgs e) + void ListView_ColumnClick(object sender, ColumnClickEventArgs e) { if (comparer.SortColumn == e.Column) { - if (comparer.Sorting == SortOrder.Ascending) - comparer.Sorting = SortOrder.Descending; - else comparer.Sorting = SortOrder.Ascending; + comparer.Sorting = comparer.Sorting == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; } else { comparer.SortColumn = e.Column; - if (e.Column >= 2) - comparer.Sorting = SortOrder.Descending; - else comparer.Sorting = SortOrder.Ascending; + comparer.Sorting = e.Column >= 2 ? SortOrder.Descending : SortOrder.Ascending; } - listView.Sort(); + ListView.Sort(); } - private void onViewObjects(object sender, EventArgs e) + void OnViewObjects(object sender, EventArgs e) { - if (listView.SelectedItems.Count == 1) + if (ListView.SelectedItems.Count == 1) { - if (OnViewObject != null) - OnViewObject(listView.SelectedItems[0].Tag as TypeItem); + OnViewObject?.Invoke(ListView.SelectedItems[0].Tag as TypeItem); } } public void Clear() { items = new Dictionary(); - listView.Items.Clear(); + ListView.Items.Clear(); } /// @@ -87,7 +77,7 @@ public void Clear() /// public void UpdateTypeGrid(string[] lines) { - listView.BeginUpdate(); + ListView.BeginUpdate(); foreach (TypeItem item in items.Values) item.Zero(); @@ -101,44 +91,42 @@ public void UpdateTypeGrid(string[] lines) { item = new TypeItem(parts[3]); items[parts[0]] = item; - listView.Items.Add(item.ListItem); + ListView.Items.Add(item.ListItem); } else if (!items.ContainsKey(parts[0])) continue; else item = items[parts[0]]; item.Update(parts[1], parts[2]); } - listView.Sort(); + ListView.Sort(); } finally { - listView.EndUpdate(); + ListView.EndUpdate(); } } } - #region Model - class TypeItemComparer : IComparer + class TypeItemComparer : IComparer, IComparer { - public int SortColumn = 0; + public int SortColumn; public SortOrder Sorting; - int IComparer.Compare(object x, object y) - { - TypeItem a = (TypeItem)((ListViewItem)x).Tag; - TypeItem b = (TypeItem)((ListViewItem)y).Tag; + public int Compare(object x, object y) => Compare((ListViewItem) x, (ListViewItem) y); - int comp; - switch (SortColumn) + public int Compare(ListViewItem x, ListViewItem y) + { + var a = (TypeItem)x.Tag; + var b = (TypeItem)y.Tag; + var comp = SortColumn switch { - case TypeItem.COL_PKG: comp = a.Package.CompareTo(b.Package); break; - case TypeItem.COL_MAX: comp = a.Maximum.CompareTo(b.Maximum); break; - case TypeItem.COL_COUNT: comp = a.Count.CompareTo(b.Count); break; - case TypeItem.COL_MEM: comp = a.Memory.CompareTo(b.Memory); break; - default: comp = a.Name.CompareTo(b.Name); break; - } - + TypeItem.COL_PKG => a.Package.CompareTo(b.Package), + TypeItem.COL_MAX => a.Maximum.CompareTo(b.Maximum), + TypeItem.COL_COUNT => a.Count.CompareTo(b.Count), + TypeItem.COL_MEM => a.Memory.CompareTo(b.Memory), + _ => a.Name.CompareTo(b.Name), + }; return Sorting == SortOrder.Ascending ? comp : -comp; } } @@ -163,15 +151,13 @@ class TypeItem public TypeItem(string fullName) { QName = fullName; - int p = fullName.IndexOf(':'); - if (p >= 0) + if (fullName.Contains(':', out var p)) { Name = fullName.Substring(p + 2); Package = fullName.Substring(0, p); } else Name = fullName; - ListItem = new ListViewItem(Name); - ListItem.Tag = this; + ListItem = new ListViewItem(Name) {Tag = this}; ListItem.SubItems.Add(new ListViewItem.ListViewSubItem(ListItem, Package)); ListItem.SubItems.Add(new ListViewItem.ListViewSubItem(ListItem, "0")); ListItem.SubItems.Add(new ListViewItem.ListViewSubItem(ListItem, "0")); @@ -205,4 +191,4 @@ public void Zero() } #endregion -} +} \ No newline at end of file diff --git a/External/Plugins/AS3Context/Controls/ProfilerMemView.cs b/External/Plugins/AS3Context/Controls/ProfilerMemView.cs index 6fde3d4dda..4f1f17f5eb 100644 --- a/External/Plugins/AS3Context/Controls/ProfilerMemView.cs +++ b/External/Plugins/AS3Context/Controls/ProfilerMemView.cs @@ -8,48 +8,41 @@ namespace AS3Context.Controls { class ProfilerMemView { - ToolStripLabel memLabel; - Label statsLabel; - ComboBox scaleCombo; - const int MAX_WIDTH = 1000; - const int MAX_HEIGHT = 400; - private MemGraph graph; - - public MemGraph Graph - { - get { return graph; } - } + readonly ToolStripLabel memLabel; + readonly Label statsLabel; + readonly ComboBox scaleCombo; + + public MemGraph Graph { get; } - public ProfilerMemView(ToolStripLabel label, Label stats, ComboBox scale, TabPage memoryPage) + public ProfilerMemView(ToolStripLabel label, Label stats, ComboBox scale, Control memoryPage) { - graph = new MemGraph(); - graph.Dock = DockStyle.Fill; - memoryPage.Controls.Add(graph); - graph.BringToFront(); + Graph = new MemGraph {Dock = DockStyle.Fill}; + memoryPage.Controls.Add(Graph); + Graph.BringToFront(); memLabel = label; statsLabel = stats; scaleCombo = scale; scaleCombo.SelectedIndex = scaleCombo.Items.Count - 1; - scaleCombo.SelectedIndexChanged += new EventHandler(scaleCombo_SelectedIndexChanged); - graph.TimeScale = scaleCombo.SelectedIndex + 1; + scaleCombo.SelectedIndexChanged += scaleCombo_SelectedIndexChanged; + Graph.TimeScale = scaleCombo.SelectedIndex + 1; Clear(); } void scaleCombo_SelectedIndexChanged(object sender, EventArgs e) { - graph.TimeScale = scaleCombo.SelectedIndex + 1; - graph.Invalidate(); + Graph.TimeScale = scaleCombo.SelectedIndex + 1; + Graph.Invalidate(); } public void Clear() { - graph.Values = new List(); - graph.MaxValue = 1; - memLabel.Text = String.Format(TextHelper.GetString("Label.MemoryDisplay"), FormatMemory(0), FormatMemory(0)); - statsLabel.Text = String.Format(TextHelper.GetString("Label.MemoryStats"), "\n", FormatMemory(0), FormatMemory(0)); + Graph.Values = new List(); + Graph.MaxValue = 1; + memLabel.Text = string.Format(TextHelper.GetString("Label.MemoryDisplay"), FormatMemory(0), FormatMemory(0)); + statsLabel.Text = string.Format(TextHelper.GetString("Label.MemoryStats"), "\n", FormatMemory(0), FormatMemory(0)); } /// @@ -58,18 +51,17 @@ public void Clear() /// public void UpdateStats(string[] info) { - int mem = 0; - int.TryParse(info[1], out mem); - graph.Values.Add((float)mem); - if (mem > graph.MaxValue) graph.MaxValue = mem; + int.TryParse(info[1], out var mem); + Graph.Values.Add(mem); + if (mem > Graph.MaxValue) Graph.MaxValue = mem; string raw = TextHelper.GetString("Label.MemoryDisplay"); - memLabel.Text = String.Format(raw, FormatMemory(mem), FormatMemory((int)graph.MaxValue)); + memLabel.Text = string.Format(raw, FormatMemory(mem), FormatMemory((int)Graph.MaxValue)); raw = TextHelper.GetString("Label.MemoryStats"); - statsLabel.Text = String.Format(raw, "\n", FormatMemory(mem), FormatMemory((int)graph.MaxValue)); - graph.Invalidate(); + statsLabel.Text = string.Format(raw, "\n", FormatMemory(mem), FormatMemory((int)Graph.MaxValue)); + Graph.Invalidate(); } - private string FormatMemory(int mem) + string FormatMemory(int mem) { double m = mem / 1024.0; return (Math.Round(m * 10.0) / 10.0).ToString("N0"); @@ -81,16 +73,16 @@ class MemGraph : Control public List Values = new List(); public float MaxValue = 1; public int TimeScale = 4; - private Color back; - private Color rect; - private Color norm; - private Color peak; - private Color cur; + Color back; + Color rect; + Color norm; + Color peak; + Color cur; public MemGraph() { - this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); - this.UpdateColors(); + SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); + UpdateColors(); } public void UpdateColors() @@ -119,11 +111,10 @@ protected override void OnPaint(PaintEventArgs pe) int diff = Math.Min(Width / TimeScale, n); int x0 = Width - diff * TimeScale; int i = Math.Max(0, n - diff); - float h = (float)Height; - Pen line; + float h = Height; // peak - line = new Pen(norm, 1); + var line = new Pen(norm, 1); float step = 25000000f; while (step * 4 < MaxValue) step *= 2; float top = step; @@ -139,15 +130,14 @@ protected override void OnPaint(PaintEventArgs pe) g.DrawLine(line, 0f, y, Width - 1, y); // graph - List points = new List(); + var points = new List(); while (i < n) { points.Add(new PointF(x0, h * (1f - 0.9f * Values[i] / MaxValue))); i++; x0 += TimeScale; } - line = new Pen(cur, 2); - line.LineJoin = System.Drawing.Drawing2D.LineJoin.Round; + line = new Pen(cur, 2) {LineJoin = System.Drawing.Drawing2D.LineJoin.Round}; g.DrawLines(line, points.ToArray()); } diff --git a/External/Plugins/AS3Context/Controls/ProfilerObjectsView.cs b/External/Plugins/AS3Context/Controls/ProfilerObjectsView.cs index 9cd2c1a1d1..61fd012a61 100644 --- a/External/Plugins/AS3Context/Controls/ProfilerObjectsView.cs +++ b/External/Plugins/AS3Context/Controls/ProfilerObjectsView.cs @@ -4,83 +4,67 @@ using System.Windows.Forms; using PluginCore; using PluginCore.Localization; -using ScintillaNet; namespace AS3Context.Controls { class ProfilerObjectsView { - ObjectRefsGrid objectsGrid; - Regex reStep = new Regex("([^\\[]+)\\[(.*):([0-9]+)\\]"); - ObjectRefsModel model = new ObjectRefsModel(); - ToolStripMenuItem openItem; + readonly Regex reStep = new Regex("([^\\[]+)\\[(.*):([0-9]+)\\]"); + readonly ObjectRefsModel model = new ObjectRefsModel(); string fileToOpen; int lineToOpen; - Timer delayOpen; + readonly Timer delayOpen; - public ObjectRefsGrid ObjectsGrid - { - get { return objectsGrid; } - } + public ObjectRefsGrid ObjectsGrid { get; } public ProfilerObjectsView(ObjectRefsGrid grid) { - objectsGrid = grid; + ObjectsGrid = grid; delayOpen = new Timer(); delayOpen.Interval = 100; - delayOpen.Tick += new EventHandler(delayOpen_Tick); + delayOpen.Tick += delayOpen_Tick; // action - openItem = new ToolStripMenuItem(TextHelper.GetString("Label.OpenMethodFile")); - openItem.Click += new EventHandler(objectsGrid_Open); + var openItem = new ToolStripMenuItem(TextHelper.GetString("Label.OpenMethodFile")); + openItem.Click += objectsGrid_Open; - objectsGrid.ContextMenuStrip = new ContextMenuStrip(); - objectsGrid.ContextMenuStrip.Font = PluginBase.Settings.DefaultFont; - objectsGrid.ContextMenuStrip.Renderer = new DockPanelStripRenderer(false); - objectsGrid.ContextMenuStrip.Items.Add(openItem); - objectsGrid.DoubleClick += new EventHandler(objectsGrid_Open); + ObjectsGrid.ContextMenuStrip = new ContextMenuStrip(); + ObjectsGrid.ContextMenuStrip.Font = PluginBase.Settings.DefaultFont; + ObjectsGrid.ContextMenuStrip.Renderer = new DockPanelStripRenderer(false); + ObjectsGrid.ContextMenuStrip.Items.Add(openItem); + ObjectsGrid.DoubleClick += objectsGrid_Open; } void delayOpen_Tick(object sender, EventArgs e) { delayOpen.Stop(); - if (fileToOpen != null) + if (fileToOpen is null) return; + if (File.Exists(fileToOpen)) { - if (File.Exists(fileToOpen)) + PluginBase.MainForm.OpenEditableDocument(fileToOpen, false); + if (PluginBase.MainForm.CurrentDocument is {IsEditable: true, SciControl: { } sci} doc + && doc.FileName.Equals(fileToOpen, StringComparison.OrdinalIgnoreCase)) { - PluginBase.MainForm.OpenEditableDocument(fileToOpen, false); - if (PluginBase.MainForm.CurrentDocument.IsEditable - && PluginBase.MainForm.CurrentDocument.FileName.Equals(fileToOpen, StringComparison.OrdinalIgnoreCase)) - { - ScintillaControl sci = PluginBase.MainForm.CurrentDocument.SciControl; - int pos = sci.PositionFromLine(lineToOpen); - sci.SetSel(pos, pos); - sci.EnsureVisibleEnforcePolicy(lineToOpen); - } + var pos = sci.PositionFromLine(lineToOpen); + sci.SetSel(pos, pos); + sci.EnsureVisibleEnforcePolicy(lineToOpen); } - fileToOpen = null; } + fileToOpen = null; } void objectsGrid_Open(object sender, EventArgs e) { - if (objectsGrid.SelectedNode != null) + if (ObjectsGrid.SelectedNode?.Tag is ObjectRefsNode node && node.Line.Length > 0) { - ObjectRefsNode node = objectsGrid.SelectedNode.Tag as ObjectRefsNode; - if (node != null && node.Line.Length > 0) - { - fileToOpen = node.Path.Replace(';', Path.DirectorySeparatorChar); - lineToOpen = int.Parse(node.Line) - 1; - delayOpen.Start(); - } + fileToOpen = node.Path.Replace(';', Path.DirectorySeparatorChar); + lineToOpen = int.Parse(node.Line) - 1; + delayOpen.Start(); } } - public void Clear() - { - model.Root.Nodes.Clear(); - } + public void Clear() => model.Root.Nodes.Clear(); public void Display(string qname, string[] info) { @@ -107,7 +91,7 @@ public void Display(string qname, string[] info) model.Root.Nodes.Add(node); } - objectsGrid.Model = model; + ObjectsGrid.Model = model; } } } diff --git a/External/Plugins/AS3Context/Controls/ProfilerUI.cs b/External/Plugins/AS3Context/Controls/ProfilerUI.cs index fbfc0bd426..9628d14ff5 100644 --- a/External/Plugins/AS3Context/Controls/ProfilerUI.cs +++ b/External/Plugins/AS3Context/Controls/ProfilerUI.cs @@ -10,52 +10,45 @@ using System.Net.Sockets; using System.Text.RegularExpressions; using System.Collections.Generic; +using System.Linq; using WeifenLuo.WinFormsUI.Docking; namespace AS3Context.Controls { public partial class ProfilerUI : DockPanelControl, IThemeHandler { - static private readonly Byte[] RESULT_OK = Encoding.Default.GetBytes("\0"); - static private readonly Byte[] RESULT_IGNORED = Encoding.Default.GetBytes("\0"); - static private readonly Byte[] RESULT_GC = Encoding.Default.GetBytes("\0"); + static readonly byte[] RESULT_OK = Encoding.Default.GetBytes("\0"); + static readonly byte[] RESULT_IGNORED = Encoding.Default.GetBytes("\0"); + static readonly byte[] RESULT_GC = Encoding.Default.GetBytes("\0"); - static private ProfilerUI instance; - static private bool gcWanted; - static private byte[] snapshotWanted; + static ProfilerUI instance; + static bool gcWanted; + static byte[] snapshotWanted; public DockContent PanelRef; - private bool autoStart; - private bool running; - private string current; - private List previous = new List(); - private ObjectRefsGrid objectRefsGrid; - private ProfilerLiveObjectsView liveObjectsView; - private ProfilerMemView memView; - private ProfilerObjectsView objectRefsView; - private Timer detectDisconnect; - private List profilerItems; - private string profilerItemsCheck; - private string profilerSWF; - - public bool AutoStart - { - get { return autoStart; } - } + bool running; + string current; + readonly List previous = new List(); + readonly ObjectRefsGrid objectRefsGrid; + readonly ProfilerLiveObjectsView liveObjectsView; + readonly ProfilerMemView memView; + readonly ProfilerObjectsView objectRefsView; + readonly Timer detectDisconnect; + List profilerItems; + string profilerItemsCheck; + string profilerSWF; + + public bool AutoStart { get; private set; } public static void HandleFlashConnect(object sender, object data) { - Socket client = sender as Socket; - - if (instance == null || data == null || !instance.running) + var client = (Socket) sender; + if (instance is null || data is null || !instance.running) { if (client.Connected) client.Send(RESULT_IGNORED); return; } - instance.OnProfileData((string)data); - if (client.Connected) client.Send(RESULT_OK); - if (gcWanted) { if (client.Connected) client.Send(RESULT_GC); @@ -91,7 +84,7 @@ public ProfilerUI() if (PluginMain.Settings.ProfilerTimeout == 0) PluginMain.Settings.ProfilerTimeout = 30; detectDisconnect = new Timer(); detectDisconnect.Interval = Math.Max(5, PluginMain.Settings.ProfilerTimeout) * 1000; - detectDisconnect.Tick += new EventHandler(detectDisconnect_Tick); + detectDisconnect.Tick += detectDisconnect_Tick; memView = new ProfilerMemView(memLabel, memStatsLabel, memScaleCombo, memoryPage); @@ -99,10 +92,10 @@ public ProfilerUI() column.Width = ScaleHelper.Scale(column.Width); liveObjectsView = new ProfilerLiveObjectsView(listView); - liveObjectsView.OnViewObject += new ViewObjectEvent(liveObjectsView_OnViewObject); + liveObjectsView.OnViewObject += liveObjectsView_OnViewObject; objectRefsView = new ProfilerObjectsView(objectRefsGrid); - configureProfilerChooser(); + ConfigureProfilerChooser(); StopProfiling(); } @@ -124,7 +117,7 @@ void liveObjectsView_OnViewObject(TypeItem item) tabControl.SelectedTab = objectsPage; } - private void InitializeLocalization() + void InitializeLocalization() { this.labelTarget.Text = ""; this.autoButton.Text = TextHelper.GetString("Label.AutoStartProfilerOFF"); @@ -154,13 +147,13 @@ public void Cleanup() SetProfilerCfg(false); } - private void runButton_Click(object sender, EventArgs e) + void runButton_Click(object sender, EventArgs e) { if (running) StopProfiling(); else StartProfiling(); } - private void gcButton_Click(object sender, EventArgs e) + void gcButton_Click(object sender, EventArgs e) { if (running && current != null) gcWanted = true; } @@ -192,50 +185,48 @@ public void StartProfiling() gcButton.Enabled = false; if (!SetProfilerCfg(true)) StopProfiling(); - else if (autoStart) + else if (AutoStart) { detectDisconnect.Interval = 5000; // expecting connection before 5s detectDisconnect.Start(); } } - private void autoButton_Click(object sender, EventArgs e) + void autoButton_Click(object sender, EventArgs e) { - autoStart = !autoStart; - autoButton.Image = PluginBase.MainForm.FindImage(autoStart ? "510" : "514"); - autoButton.Text = TextHelper.GetString(autoStart ? "Label.AutoStartProfilerON" : "Label.AutoStartProfilerOFF"); + AutoStart = !AutoStart; + autoButton.Image = PluginBase.MainForm.FindImage(AutoStart ? "510" : "514"); + autoButton.Text = TextHelper.GetString(AutoStart ? "Label.AutoStartProfilerON" : "Label.AutoStartProfilerOFF"); } #endregion #region Profiler selector - private void configureProfilerChooser() + void ConfigureProfilerChooser() { profilerChooser.Image = PluginBase.MainForm.FindImage("274"); - profilerChooser.DropDownOpening += new EventHandler(profilerChooser_DropDownOpening); + profilerChooser.DropDownOpening += ProfilerChooser_DropDownOpening; profilerItems = new List(); defaultToolStripMenuItem.Checked = true; - defaultToolStripMenuItem.Click += new EventHandler(changeProfiler_Click); + defaultToolStripMenuItem.Click += ChangeProfiler_Click; profilerSWF = null; // default - string active = Path.Combine(Path.Combine(PathHelper.DataDir, "AS3Context"), "activeProfiler.txt"); + var active = Path.Combine(PathHelper.DataDir, "AS3Context", "activeProfiler.txt"); if (File.Exists(active)) { - string src = File.ReadAllText(active).Trim(); - if (src.Length > 0 && File.Exists(src)) - profilerSWF = src; + var src = File.ReadAllText(active).Trim(); + if (File.Exists(src)) profilerSWF = src; } } - void profilerChooser_DropDownOpening(object sender, EventArgs e) + void ProfilerChooser_DropDownOpening(object sender, EventArgs e) { - string[] swfs = PluginMain.Settings.CustomProfilers; - if (swfs == null || swfs.Length == 0) return; + var swfs = PluginMain.Settings.CustomProfilers; + if (swfs.IsNullOrEmpty()) return; - string check = ""; - foreach(string swf in swfs) check += swf; + var check = swfs.Aggregate("", (current1, swf) => current1 + swf); if (check == profilerItemsCheck) return; profilerItemsCheck = check; @@ -248,7 +239,7 @@ void profilerChooser_DropDownOpening(object sender, EventArgs e) { ToolStripMenuItem item = new ToolStripMenuItem(Path.GetFileNameWithoutExtension(swf)); item.Tag = swf; - item.Click += new EventHandler(changeProfiler_Click); + item.Click += ChangeProfiler_Click; profilerItems.Add(item); } } @@ -256,24 +247,24 @@ void profilerChooser_DropDownOpening(object sender, EventArgs e) profilerChooser.DropDownItems.AddRange(profilerItems.ToArray()); defaultToolStripMenuItem.Checked = false; foreach (ToolStripMenuItem item in profilerItems) - if (item.Tag as String == profilerSWF) + if (item.Tag as string == profilerSWF) { item.Checked = true; break; } } - void changeProfiler_Click(object sender, EventArgs e) + void ChangeProfiler_Click(object sender, EventArgs e) { - ToolStripMenuItem item = sender as ToolStripMenuItem; - if (item == null || item.Checked) return; + var item = sender as ToolStripMenuItem; + if (item is null || item.Checked) return; - foreach (ToolStripMenuItem it in profilerItems) + foreach (var it in profilerItems) it.Checked = false; item.Checked = true; - profilerSWF = item.Tag as String; + profilerSWF = item.Tag as string; - string active = Path.Combine(Path.Combine(PathHelper.DataDir, "AS3Context"), "activeProfiler.txt"); + var active = Path.Combine(PathHelper.DataDir, "AS3Context", "activeProfiler.txt"); File.WriteAllText(active, profilerSWF ?? ""); } @@ -327,14 +318,13 @@ internal bool OnProfileData(string data) #region MM configuration - private bool SetProfilerCfg(bool active) + bool SetProfilerCfg(bool active) { try { - String mmCfg = PathHelper.ResolveMMConfig(); + var mmCfg = PathHelper.ResolveMMConfig(); if (!File.Exists(mmCfg)) CreateDefaultCfg(mmCfg); - - string src = File.ReadAllText(mmCfg).Trim(); + var src = File.ReadAllText(mmCfg).Trim(); src = Regex.Replace(src, "PreloadSwf=.*", "").Trim(); if (active) { @@ -349,67 +339,59 @@ private bool SetProfilerCfg(bool active) return true; } - private string AddDefaultProfiler() + static string AddDefaultProfiler() { string swfPath = ResolvePath(CheckResource("Profiler5.swf", "Profiler.swf")); ASCompletion.Commands.CreateTrustFile.Run("FDProfiler.cfg", Path.GetDirectoryName(swfPath)); - FlashConnect.Settings settings = GetFlashConnectSettings(); + var settings = GetFlashConnectSettings(); return "\r\nPreloadSwf=" + swfPath + "?host=" + settings.Host + "&port=" + settings.Port + "\r\n"; } - private string AddCustomProfiler() + string AddCustomProfiler() { - string swfPath = ResolvePath(profilerSWF); - if (swfPath == null) return null; - ASCompletion.Commands.CreateTrustFile.Run("FDProfiler.cfg", Path.GetDirectoryName(swfPath)); - return "\r\nPreloadSwf=" + swfPath + "\r\n"; + var path = ResolvePath(profilerSWF); + if (path is null) return null; + ASCompletion.Commands.CreateTrustFile.Run("FDProfiler.cfg", Path.GetDirectoryName(path)); + return "\r\nPreloadSwf=" + path + "\r\n"; } - private string ResolvePath(string path) + static string ResolvePath(string path) { - if (PluginBase.CurrentProject != null) - return PathHelper.ResolvePath(path, Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath)); - else - return PathHelper.ResolvePath(path); + return PluginBase.CurrentProject != null + ? PathHelper.ResolvePath(path, Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath)) + : PathHelper.ResolvePath(path); } - private FlashConnect.Settings GetFlashConnectSettings() + static FlashConnect.Settings GetFlashConnectSettings() { - IPlugin flashConnect = PluginBase.MainForm.FindPlugin("425ae753-fdc2-4fdf-8277-c47c39c2e26b"); - return flashConnect != null ? (FlashConnect.Settings)flashConnect.Settings : new FlashConnect.Settings(); + var plugin = PluginBase.MainForm.FindPlugin("425ae753-fdc2-4fdf-8277-c47c39c2e26b"); + return plugin != null ? (FlashConnect.Settings)plugin.Settings : new FlashConnect.Settings(); } - static private string CheckResource(string fileName, string resName) + static string CheckResource(string fileName, string resName) { - string path = Path.Combine(PathHelper.DataDir, "AS3Context"); - string fullPath = Path.Combine(path, fileName); - if (!File.Exists(fullPath)) + var fullPath = Path.Combine(PathHelper.DataDir, "AS3Context", fileName); + if (File.Exists(fullPath)) return fullPath; + var id = "AS3Context.Resources." + resName; + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + using var br = new BinaryReader(assembly.GetManifestResourceStream(id)); + using var bw = File.Create(fullPath); + var buffer = br.ReadBytes(1024); + while (buffer.Length > 0) { - string id = "AS3Context.Resources." + resName; - System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); - using (BinaryReader br = new BinaryReader(assembly.GetManifestResourceStream(id))) - { - using (FileStream bw = File.Create(fullPath)) - { - byte[] buffer = br.ReadBytes(1024); - while (buffer.Length > 0) - { - bw.Write(buffer, 0, buffer.Length); - buffer = br.ReadBytes(1024); - } - bw.Close(); - } - br.Close(); - } + bw.Write(buffer, 0, buffer.Length); + buffer = br.ReadBytes(1024); } + bw.Close(); + br.Close(); return fullPath; } - private void CreateDefaultCfg(string mmCfg) + static void CreateDefaultCfg(string mmCfg) { try { - String contents = "PolicyFileLog=1\r\nPolicyFileLogAppend=0\r\nErrorReportingEnable=1\r\nTraceOutputFileEnable=1\r\n"; + const string contents = "PolicyFileLog=1\r\nPolicyFileLogAppend=0\r\nErrorReportingEnable=1\r\nTraceOutputFileEnable=1\r\n"; FileHelper.WriteFile(mmCfg, contents, Encoding.UTF8); } catch (Exception ex) @@ -421,7 +403,4 @@ private void CreateDefaultCfg(string mmCfg) #endregion } - - - -} +} \ No newline at end of file diff --git a/External/Plugins/AS3Context/MxmlComplete.cs b/External/Plugins/AS3Context/MxmlComplete.cs index b64f9b3917..0506b3edd4 100644 --- a/External/Plugins/AS3Context/MxmlComplete.cs +++ b/External/Plugins/AS3Context/MxmlComplete.cs @@ -12,22 +12,21 @@ using PluginCore; using PluginCore.Controls; using PluginCore.Helpers; -using ScintillaNet; using XMLCompletion; namespace AS3Context { class MxmlComplete { - static public bool IsDirty; - static public Context context; - static public MxmlFilterContext mxmlContext; + public static bool IsDirty; + public static Context context; + public static MxmlFilterContext mxmlContext; #region shortcuts public static bool GotoDeclaration() { - ScintillaControl sci = PluginBase.MainForm.CurrentDocument.SciControl; - if (sci == null) return false; + var sci = PluginBase.MainForm.CurrentDocument?.SciControl; + if (sci is null) return false; if (sci.ConfigurationLanguage != "xml") return false; int pos = sci.CurrentPos; @@ -38,13 +37,11 @@ public static bool GotoDeclaration() if (c <= 32 || c == '/' || c == '>') break; pos ++; } - XMLContextTag ctag = XMLComplete.GetXMLContextTag(sci, pos); - if (ctag.Name == null) return true; + var ctag = XMLComplete.GetXMLContextTag(sci, pos); + if (ctag.Name is null) return true; string word = sci.GetWordFromPosition(sci.CurrentPos); - string type = ResolveType(mxmlContext, ctag.Name); - ClassModel model = context.ResolveType(type, mxmlContext.model); - + var model = context.ResolveType(type, mxmlContext.model); if (model.IsVoid()) // try resolving tag as member of parent tag { parentTag = XMLComplete.GetParentTag(sci, ctag); @@ -60,14 +57,12 @@ public static bool GotoDeclaration() if (word != null && !ctag.Name.EndsWithOrdinal(word)) { - ASResult found = ResolveAttribute(model, word); + var found = ResolveAttribute(model, word); ASComplete.OpenDocumentToDeclaration(sci, found); } else { - ASResult found = new ASResult(); - found.InFile = model.InFile; - found.Type = model; + var found = new ASResult {InFile = model.InFile, Type = model}; ASComplete.OpenDocumentToDeclaration(sci, found); } return true; @@ -75,21 +70,23 @@ public static bool GotoDeclaration() #endregion #region tag completion - static private XMLContextTag tagContext; - static private XMLContextTag parentTag; - static private string tokenContext; - static private string checksum; - static private Dictionary> allTags; + + static XMLContextTag tagContext; + static XMLContextTag parentTag; + static string tokenContext; + static string checksum; + + static Dictionary> allTags; //static private Regex reIncPath = new Regex("[\"']([^\"']+)", RegexOptions.Compiled); - static private Regex reIncPath = new Regex("(\"|')([^\r\n]+)(\\1)", RegexOptions.Compiled); - static private Dictionary includesCache = new Dictionary(); + static readonly Regex reIncPath = new Regex("(\"|')([^\r\n]+)(\\1)", RegexOptions.Compiled); + static readonly Dictionary includesCache = new Dictionary(); /// /// Called /// /// /// - static public bool HandleElement(object data) + public static bool HandleElement(object data) { if (!GetContext(data)) return false; @@ -102,19 +99,19 @@ static public bool HandleElement(object data) bool isContainer = AddParentAttributes(mix, excludes); // current tag attributes if (isContainer) // container children tag - foreach (string ns in mxmlContext.namespaces.Keys) - { - string uri = mxmlContext.namespaces[ns]; - if (ns != "*") mix.Add(new NamespaceItem(ns, uri)); - - if (!allTags.ContainsKey(ns)) - continue; - foreach (string tag in allTags[ns]) + foreach (string ns in mxmlContext.namespaces.Keys) { - if (ns == "*") mix.Add(new HtmlTagItem(tag, tag)); - else mix.Add(new HtmlTagItem(tag, ns + ":" + tag, uri)); + string uri = mxmlContext.namespaces[ns]; + if (ns != "*") mix.Add(new NamespaceItem(ns, uri)); + + if (!allTags.ContainsKey(ns)) + continue; + foreach (string tag in allTags[ns]) + { + if (ns == "*") mix.Add(new HtmlTagItem(tag, tag)); + else mix.Add(new HtmlTagItem(tag, ns + ":" + tag, uri)); + } } - } // cleanup and show list mix.Sort(new MXMLListItemComparer()); @@ -135,7 +132,7 @@ static public bool HandleElement(object data) return true; } - private static bool AddParentAttributes(List mix, List excludes) + static bool AddParentAttributes(List mix, List excludes) { bool isContainer = true; if (parentTag.Name != null) // add parent tag members @@ -147,8 +144,8 @@ private static bool AddParentAttributes(List mix, List mix, List mix = new List(); - List excludes = new List(); - - bool isContainer = AddParentAttributes(mix, excludes); // current tag attributes - + var ns = tagContext.Name.Substring(0, p); + if (!mxmlContext.namespaces.ContainsKey(ns)) return true; + var uri = mxmlContext.namespaces[ns]; + var mix = new List(); + var excludes = new List(); + var isContainer = AddParentAttributes(mix, excludes); // current tag attributes if (isContainer && allTags.ContainsKey(ns)) // container children tags foreach (string tag in allTags[ns]) mix.Add(new HtmlTagItem(tag, ns + ":" + tag, uri)); // cleanup and show list mix.Sort(new MXMLListItemComparer()); - List items = new List(); + var items = new List(); string previous = null; - foreach (ICompletionListItem item in mix) + foreach (var item in mix) { if (previous == item.Label) continue; previous = item.Label; @@ -198,15 +189,13 @@ static public bool HandleNamespace(object data) return true; } - static public bool HandleElementClose(object data) + public static bool HandleElementClose(object data) { if (!GetContext(data)) return false; - if (tagContext.Closing) return false; - - string type = ResolveType(mxmlContext, tagContext.Name); - ScintillaControl sci = PluginBase.MainForm.CurrentDocument.SciControl; - + var sci = PluginBase.MainForm.CurrentDocument?.SciControl; + if (sci is null) return false; + var type = ResolveType(mxmlContext, tagContext.Name); if (type.StartsWithOrdinal("mx.builtin.") || type.StartsWithOrdinal("fx.builtin.")) // special tags { if (type.EndsWithOrdinal(".Script")) @@ -222,7 +211,7 @@ static public bool HandleElementClose(object data) { string uri = mxmlContext.namespaces[ns]; if (ns != "fx") - snip += String.Format("\n\t@namespace {0} \"{1}\";", ns, uri); + snip += $"\n\t@namespace {ns} \"{uri}\";"; } snip += "\n\t$(EntryPoint)\n"; SnippetHelper.InsertSnippetText(sci, sci.CurrentPos, snip); @@ -232,31 +221,28 @@ static public bool HandleElementClose(object data) return false; } - static public bool HandleAttribute(object data) + public static bool HandleAttribute(object data) { if (!GetContext(data)) return false; - - string type = ResolveType(mxmlContext, tagContext.Name); - ClassModel tagClass = context.ResolveType(type, mxmlContext.model); + var type = ResolveType(mxmlContext, tagContext.Name); + var tagClass = context.ResolveType(type, mxmlContext.model); if (tagClass.IsVoid()) return true; tagClass.ResolveExtends(); - - List mix = new List(); - List excludes = new List(); + var mix = new List(); + var excludes = new List(); GetTagAttributes(tagClass, mix, excludes, null); // cleanup and show list mix.Sort(new MXMLListItemComparer()); - List items = new List(); + var items = new List(); string previous = null; - foreach (ICompletionListItem item in mix) + foreach (var item in mix) { if (previous == item.Label) continue; previous = item.Label; if (excludes.Contains(previous)) continue; items.Add(item); } - if (items.Count == 0) return true; if (!string.IsNullOrEmpty(tokenContext)) CompletionList.Show(items, false, tokenContext); else CompletionList.Show(items, true); @@ -264,17 +250,14 @@ static public bool HandleAttribute(object data) return true; } - static public bool HandleAttributeValue(object data) + public static bool HandleAttributeValue(object data) { if (!GetContext(data)) return false; - - string type = ResolveType(mxmlContext, tagContext.Name); - ClassModel tagClass = context.ResolveType(type, mxmlContext.model); + var type = ResolveType(mxmlContext, tagContext.Name); + var tagClass = context.ResolveType(type, mxmlContext.model); if (tagClass.IsVoid()) return true; tagClass.ResolveExtends(); - - string currentAttribute; - StringBuilder caBuilder = new StringBuilder(); + var caBuilder = new StringBuilder(); bool possibleStartFound = false, startFound = false; for (int i = tagContext.Tag.Length - 1; i >= 0; i--) { @@ -285,29 +268,28 @@ static public bool HandleAttributeValue(object data) } else if (startFound) { - if (Char.IsWhiteSpace(currChar)) + if (char.IsWhiteSpace(currChar)) break; caBuilder.Insert(0, currChar); } - else if (possibleStartFound && !Char.IsWhiteSpace(currChar)) + else if (possibleStartFound && !char.IsWhiteSpace(currChar)) { startFound = true; caBuilder.Insert(0, currChar); } } - currentAttribute = caBuilder.ToString(); + var currentAttribute = caBuilder.ToString(); - List mix = GetTagAttributeValues(tagClass, null, currentAttribute); - - if (mix == null || mix.Count == 0) return true; + var mix = GetTagAttributeValues(tagClass, null, currentAttribute); + if (mix.IsNullOrEmpty()) return true; // cleanup and show list mix.Sort(new MXMLListItemComparer()); - List items = new List(); + var items = new List(); string previous = null; - foreach (ICompletionListItem item in mix) + foreach (var item in mix) { if (previous == item.Label) continue; previous = item.Label; @@ -321,13 +303,13 @@ static public bool HandleAttributeValue(object data) return true; } - private static bool GetTagAttributes(ClassModel tagClass, List mix, List excludes, string ns) + static bool GetTagAttributes(ClassModel tagClass, ICollection mix, ICollection excludes, string ns) { - ClassModel curClass = mxmlContext.model.GetPublicClass(); - ClassModel tmpClass = tagClass; - FlagType mask = FlagType.Variable | FlagType.Setter; - Visibility acc = context.TypesAffinity(curClass, tmpClass); - bool isContainer = false; + var curClass = mxmlContext.model.GetPublicClass(); + var tmpClass = tagClass; + var mask = FlagType.Variable | FlagType.Setter; + var acc = context.TypesAffinity(curClass, tmpClass); + var isContainer = false; if (tmpClass.InFile.Package != "mx.builtin" && tmpClass.InFile.Package != "fx.builtin") mix.Add(new HtmlAttributeItem("id", "String", null, ns)); @@ -356,9 +338,7 @@ private static bool GetTagAttributes(ClassModel tagClass, List 0) { - if (member.Parameters != null && member.Parameters.Count > 0) - mtype = member.Parameters[0].Type; - else mtype = null; + mtype = !member.Parameters.IsNullOrEmpty() ? member.Parameters[0].Type : null; } mix.Add(new HtmlAttributeItem(member.Name, mtype, className, ns)); } @@ -366,7 +346,7 @@ private static bool GetTagAttributes(ClassModel tagClass, List GetTagAttributeValues(ClassModel tagClass, string ns, string attribute) + static List GetTagAttributeValues(ClassModel tagClass, string ns, string attribute) { - ClassModel curClass = mxmlContext.model.GetPublicClass(); - ClassModel tmpClass = tagClass; - FlagType mask = FlagType.Variable | FlagType.Setter | FlagType.Getter; - Visibility acc = context.TypesAffinity(curClass, tmpClass); + var curClass = mxmlContext.model.GetPublicClass(); + var tmpClass = tagClass; + var mask = FlagType.Variable | FlagType.Setter | FlagType.Getter; + var acc = context.TypesAffinity(curClass, tmpClass); if (tmpClass.InFile.Package != "mx.builtin" && tmpClass.InFile.Package != "fx.builtin" && attribute == "id") return null; @@ -402,10 +382,7 @@ private static List GetTagAttributeValues(ClassModel tagCla if ((member.Flags & FlagType.Setter) > 0) { - if (member.Parameters != null && member.Parameters.Count > 0) - mtype = member.Parameters[0].Type; - else mtype = null; - + mtype = !member.Parameters.IsNullOrEmpty() ? member.Parameters[0].Type : null; if (!hasGetterSetter) { hasGetterSetter = true; @@ -414,7 +391,8 @@ private static List GetTagAttributeValues(ClassModel tagCla } return GetAutoCompletionValuesFromInspectable(mtype, metas); } - else if ((member.Flags & FlagType.Getter) > 0) + + if ((member.Flags & FlagType.Getter) > 0) { if (!hasGetterSetter) { @@ -435,7 +413,7 @@ private static List GetTagAttributeValues(ClassModel tagCla return retVal; tmpClass = tmpClass.Extends; - if (tmpClass != null && tmpClass.InFile.Package == "" && tmpClass.Name == "Object") + if (tmpClass.InFile.Package == "" && tmpClass.Name == "Object") break; // members visibility acc = context.TypesAffinity(curClass, tmpClass); @@ -447,11 +425,9 @@ private static List GetTagAttributeValues(ClassModel tagCla return null; } - private static List GetAutoCompletionValuesFromInspectable(string type, List metas) + static List GetAutoCompletionValuesFromInspectable(string type, List metas) { - if (metas == null || metas.Count == 0) - return GetAutoCompletionValuesFromType(type); - + if (metas.IsNullOrEmpty()) return GetAutoCompletionValuesFromType(type); foreach (var meta in metas) { if (meta.Name != "Inspectable") continue; @@ -463,7 +439,7 @@ private static List GetAutoCompletionValuesFromInspectable( foreach (string value in enumValues.Split(',')) { var tValue = value.Trim(); - if (tValue != string.Empty) retVal.Add(new HtmlAttributeItem(tValue)); + if (tValue.Length != 0) retVal.Add(new HtmlAttributeItem(tValue)); } if (retVal.Count > 0) return retVal; @@ -473,26 +449,23 @@ private static List GetAutoCompletionValuesFromInspectable( return GetAutoCompletionValuesFromType(type); } - private static bool GetAutoCompletionValuesFromMetaData(ClassModel model, string attribute, ClassModel tagClass, ClassModel tmpClass, out List result) + static bool GetAutoCompletionValuesFromMetaData(ClassModel model, string attribute, ClassModel tagClass, ClassModel tmpClass, out List result) { - if (model != null && model.MetaDatas != null) + if (model?.MetaDatas != null) { foreach (ASMetaData meta in model.MetaDatas) { - string name = null; - if (!meta.Params.TryGetValue("name", out name) || name != attribute) continue; + if (!meta.Params.TryGetValue("name", out var name) || name != attribute) continue; string type = null; switch (meta.Kind) { case ASMetaKind.Event: - string eventType; - if (!meta.Params.TryGetValue("type", out eventType)) eventType = "flash.events.Event"; + if (!meta.Params.TryGetValue("type", out var eventType)) eventType = "flash.events.Event"; result = GetAutoCompletionValuesFromEventType(eventType); return true; case ASMetaKind.Style: - string inherit; - if (meta.Params.TryGetValue("inherit", out inherit) && inherit == "no" && tagClass != tmpClass) + if (meta.Params.TryGetValue("inherit", out var inherit) && inherit == "no" && tagClass != tmpClass) continue; meta.Params.TryGetValue("type", out type); break; @@ -512,7 +485,7 @@ private static bool GetAutoCompletionValuesFromMetaData(ClassModel model, string foreach (string value in meta.Params["enumeration"].Split(',')) { var tValue = value.Trim(); - if (tValue != string.Empty) retVal.Add(new HtmlAttributeItem(tValue)); + if (tValue.Length != 0) retVal.Add(new HtmlAttributeItem(tValue)); } result = retVal; @@ -529,7 +502,7 @@ private static bool GetAutoCompletionValuesFromMetaData(ClassModel model, string return false; } - private static List GetAutoCompletionValuesFromEventType(string type) + static List GetAutoCompletionValuesFromEventType(string type) { ClassModel tmpClass = mxmlContext.model.GetPublicClass(); ClassModel eventClass = context.ResolveType(type, mxmlContext.model); @@ -540,10 +513,10 @@ private static List GetAutoCompletionValuesFromEventType(st List result = null; var validTypes = new Dictionary(); - while (tmpClass != null && !tmpClass.IsVoid()) + while (!tmpClass.IsVoid()) { foreach (MemberModel member in tmpClass.Members) - if ((member.Flags & FlagType.Function) > 0 && (member.Access & acc) > 0 && member.Parameters != null && member.Parameters.Count > 0) + if ((member.Flags & FlagType.Function) > 0 && (member.Access & acc) > 0 && !member.Parameters.IsNullOrEmpty()) { bool validFunction = true; var argType = member.Parameters[0].Type; @@ -572,12 +545,12 @@ private static List GetAutoCompletionValuesFromEventType(st if (!validFunction) continue; - if (result == null) result = new List(); + result ??= new List(); result.Add(new MxmlEventHandlerItem(member)); } tmpClass = tmpClass.Extends; - if (tmpClass != null && tmpClass.InFile.Package == "" && tmpClass.Name == "Object") + if (tmpClass.InFile.Package == "" && tmpClass.Name == "Object") break; // members visibility // TODO: Take into account namespaces! @@ -587,7 +560,7 @@ private static List GetAutoCompletionValuesFromEventType(st return result; } - private static List GetAutoCompletionValuesFromType(string type) + static List GetAutoCompletionValuesFromType(string type) { if (type == "Boolean") { @@ -597,45 +570,42 @@ private static List GetAutoCompletionValuesFromType(string new HtmlAttributeItem("false") }; } - else if (type == "Class") + + if (type == "Class") { - ASComplete.HandleAllClassesCompletion(PluginBase.MainForm.CurrentDocument.SciControl, tokenContext, - true, false); + ASComplete.HandleAllClassesCompletion(PluginBase.MainForm.CurrentDocument?.SciControl, tokenContext, + true, false); } else if (type == "Function") { - ClassModel tmpClass = mxmlContext.model.GetPublicClass(); - Visibility acc = Visibility.Default | Visibility.Internal | Visibility.Private | Visibility.Protected | Visibility.Public; - + var tmpClass = mxmlContext.model.GetPublicClass(); + var access = Visibility.Default | Visibility.Internal | Visibility.Private | Visibility.Protected | Visibility.Public; tmpClass.ResolveExtends(); - List result = null; - while (tmpClass != null && !tmpClass.IsVoid()) + while (!tmpClass.IsVoid()) { foreach (MemberModel member in tmpClass.Members) - if ((member.Flags & FlagType.Function) > 0 && (member.Access & acc) > 0) + if ((member.Flags & FlagType.Function) > 0 && (member.Access & access) > 0) { - if (result == null) result = new List(); + result ??= new List(); result.Add(new MemberItem(member)); } tmpClass = tmpClass.Extends; - if (tmpClass != null && tmpClass.InFile.Package == "" && tmpClass.Name == "Object") + if (tmpClass.InFile.Package == "" && tmpClass.Name == "Object") break; // members visibility // TODO: Take into account namespaces! - acc = Visibility.Protected | Visibility.Public; + access = Visibility.Protected | Visibility.Public; } - return result; } return null; } - private static void ExploreMetadatas(ClassModel model, List mix, List excludes, string ns, bool isCurrentModel) + static void ExploreMetadatas(ClassModel model, ICollection mix, ICollection excludes, string ns, bool isCurrentModel) { - if (model == null || model.MetaDatas == null) - return; + if (model?.MetaDatas is null) return; string className = model.IsVoid() ? Path.GetFileNameWithoutExtension(model.InFile.FileName) : model.Name; foreach (ASMetaData meta in model.MetaDatas) { @@ -645,11 +615,10 @@ private static void ExploreMetadatas(ClassModel model, List { case ASMetaKind.Event: add = ":e"; break; case ASMetaKind.Style: - string inherit; - if (meta.Params == null || !meta.Params.TryGetValue("inherit", out inherit) || inherit != "no" || isCurrentModel) + if (meta.Params is null || !meta.Params.TryGetValue("inherit", out var inherit) || inherit != "no" || isCurrentModel) { add = ":s"; - if (meta.Params == null || !meta.Params.TryGetValue("type", out type)) type = "Object"; + if (meta.Params is null || !meta.Params.TryGetValue("type", out type)) type = "Object"; } break; case ASMetaKind.Effect: @@ -669,7 +638,7 @@ private static void ExploreMetadatas(ClassModel model, List } } - private static FileModel ParseInclude(FileModel fileModel, ASMetaData meta) + static FileModel ParseInclude(FileModel fileModel, ASMetaData meta) { Match m = reIncPath.Match(meta.RawParams); if (m.Success) @@ -694,7 +663,7 @@ private static FileModel ParseInclude(FileModel fileModel, ASMetaData meta) // parse & cache if (!File.Exists(fileName)) return null; string src = File.ReadAllText(fileName); - if (src.IndexOfOrdinal("package") < 0) src = "package {" + src + "}"; + if (!src.Contains("package")) src = "package {" + src + "}"; ASFileParser parser = new ASFileParser(); FileModel model = new FileModel(path); parser.ParseSrc(model, src); @@ -707,19 +676,18 @@ private static FileModel ParseInclude(FileModel fileModel, ASMetaData meta) #endregion #region context detection - private static bool GetContext(object data) + + static bool GetContext(object data) { - if (mxmlContext == null || mxmlContext.model == null) - return false; + if (mxmlContext?.model is null) return false; - ScintillaControl sci = PluginBase.MainForm.CurrentDocument.SciControl; - if (sci == null) return false; + var sci = PluginBase.MainForm.CurrentDocument?.SciControl; + if (sci is null) return false; // XmlComplete context try { - if (data is XMLContextTag) - tagContext = (XMLContextTag)data; + if (data is XMLContextTag tag) tagContext = tag; else { object[] o = (object[])data; @@ -749,11 +717,12 @@ private static bool GetContext(object data) #endregion #region tag resolution - private static void GetAllTags() + + static void GetAllTags() { - Dictionary nss = mxmlContext.namespaces; - MemberList allClasses = context.GetAllProjectClasses(); - Dictionary packages = new Dictionary(); + var nss = mxmlContext.namespaces; + var allClasses = context.GetAllProjectClasses(); + var packages = new Dictionary(); allTags = new Dictionary>(); foreach (string key in nss.Keys) @@ -775,8 +744,8 @@ private static void GetAllTags() continue; p = model.Type.LastIndexOf('.'); - string pkg = model.Type.Substring(0, p + 1); - if (pkg == "") pkg = "*"; + var pkg = model.Type.Substring(0, p + 1); + if (pkg.Length == 0) pkg = "*"; if (packages.ContainsKey(pkg)) { string ns = packages[pkg]; @@ -787,7 +756,7 @@ private static void GetAllTags() foreach (MxmlCatalog cat in mxmlContext.catalogs) { - List cls = allTags.ContainsKey(cat.NS) ? allTags[cat.NS] : new List(); + var cls = allTags.ContainsKey(cat.NS) ? allTags[cat.NS] : new List(); cls.AddRange(cat.Keys); allTags[cat.NS] = cls; } @@ -795,10 +764,10 @@ private static void GetAllTags() public static string ResolveType(MxmlFilterContext ctx, string tag) { - if (tag == null || ctx == null) return "void"; + if (tag is null || ctx is null) return "void"; int p = tag.IndexOf(':'); if (p < 0) return ResolveType(ctx, "*", tag); - else return ResolveType(ctx, tag.Substring(0, p), tag.Substring(p + 1)); + return ResolveType(ctx, tag.Substring(0, p), tag.Substring(p + 1)); } public static string ResolveType(MxmlFilterContext ctx, string ns, string name) @@ -823,15 +792,14 @@ public static string ResolveType(MxmlFilterContext ctx, string ns, string name) return name; } - private static ASResult ResolveAttribute(ClassModel model, string word) + static ASResult ResolveAttribute(ClassModel model, string word) { - ASResult result = new ASResult(); - ClassModel curClass = mxmlContext.model.GetPublicClass(); - ClassModel tmpClass = model; - Visibility acc = context.TypesAffinity(curClass, tmpClass); + var result = new ASResult(); + var curClass = mxmlContext.model.GetPublicClass(); + var tmpClass = model; + var acc = context.TypesAffinity(curClass, tmpClass); tmpClass.ResolveExtends(); - - while (tmpClass != null && !tmpClass.IsVoid()) + while (!tmpClass.IsVoid()) { foreach (MemberModel member in tmpClass.Members) if ((member.Flags & FlagType.Dynamic) > 0 && (member.Access & acc) > 0 @@ -845,7 +813,7 @@ private static ASResult ResolveAttribute(ClassModel model, string word) if (result.InFile.Classes.Count > 0) { result.InClass = result.InFile.Classes[0]; - result.Member = result.InClass.Members.Search(member.Name, member.Flags, 0); + result.Member = result.InClass.Members.Search(member.Name, member.Flags); } } else result.Member = member; @@ -855,7 +823,7 @@ private static ASResult ResolveAttribute(ClassModel model, string word) // TODO inspect metadata & includes tmpClass = tmpClass.Extends; - if (tmpClass != null && tmpClass.InFile.Package == "" && tmpClass.Name == "Object") + if (tmpClass.InFile.Package == "" && tmpClass.Name == "Object") break; // members visibility acc = context.TypesAffinity(curClass, tmpClass); @@ -867,7 +835,6 @@ private static ASResult ResolveAttribute(ClassModel model, string word) class MXMLListItemComparer : IComparer { - public int Compare(ICompletionListItem a, ICompletionListItem b) { string a1; @@ -875,18 +842,18 @@ public int Compare(ICompletionListItem a, ICompletionListItem b) if (a.Label.Equals(b.Label, StringComparison.OrdinalIgnoreCase)) { if (a is HtmlAttributeItem && b is HtmlTagItem) return 1; - else if (b is HtmlAttributeItem && a is HtmlTagItem) return -1; + if (b is HtmlAttributeItem && a is HtmlTagItem) return -1; } - if (a is IHtmlCompletionListItem) + if (a is IHtmlCompletionListItem aItem) { - a1 = ((IHtmlCompletionListItem)a).Name; - if (a.Value.StartsWithOrdinal("mx:")) a1 += "z"; // push down mx: tags + a1 = aItem.Name; + if (aItem.Value.StartsWithOrdinal("mx:")) a1 += "z"; // push down mx: tags } else a1 = a.Label; - if (b is IHtmlCompletionListItem) + if (b is IHtmlCompletionListItem bItem) { - b1 = ((IHtmlCompletionListItem)b).Name; - if (b.Value.StartsWithOrdinal("mx:")) b1 += "z"; // push down mx: tags + b1 = bItem.Name; + if (bItem.Value.StartsWithOrdinal("mx:")) b1 += "z"; // push down mx: tags } else b1 = b.Label; return string.Compare(a1, b1); @@ -900,8 +867,8 @@ public int Compare(ICompletionListItem a, ICompletionListItem b) /// public class MxmlEventHandlerItem : ICompletionListItem { - private MemberModel member; - private int icon; + readonly MemberModel member; + readonly int icon; public MxmlEventHandlerItem(MemberModel oMember) { @@ -909,31 +876,13 @@ public MxmlEventHandlerItem(MemberModel oMember) icon = PluginUI.GetIcon(member.Flags, member.Access); } - public string Label - { - get { return member.FullName; } - } + public string Label => member.FullName; - public string Description - { - get - { - return ClassModel.MemberDeclaration(member) + ASDocumentation.GetTipDetails(member, null); - } - } + public string Description => ClassModel.MemberDeclaration(member) + ASDocumentation.GetTipDetails(member, null); - public Bitmap Icon - { - get { return (Bitmap)ASContext.Panel.GetIcon(icon); } - } + public Bitmap Icon => (Bitmap)ASContext.Panel.GetIcon(icon); - public string Value - { - get - { - return member.Name + "(event)"; - } - } + public string Value => member.Name + "(event)"; } #endregion diff --git a/External/Plugins/AS3Context/MxmlFilter.cs b/External/Plugins/AS3Context/MxmlFilter.cs index ecfe5e78de..0d10403dfe 100644 --- a/External/Plugins/AS3Context/MxmlFilter.cs +++ b/External/Plugins/AS3Context/MxmlFilter.cs @@ -24,65 +24,56 @@ class MxmlFilterContext #region MXML Filter class MxmlFilter { - static private readonly Regex tagName = new Regex("<(?[a-z][a-z0-9_:]*)[\\s>]", RegexOptions.Compiled | RegexOptions.IgnoreCase); - static public string OLD_MX = "http://www.adobe.com/2006/mxml"; - static public string BETA_MX = "library://ns.adobe.com/flex/halo"; - static public string NEW_MX = "library://ns.adobe.com/flex/mx"; + static readonly Regex tagName = new Regex("<(?[a-z][a-z0-9_:]*)[\\s>]", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static string OLD_MX = "http://www.adobe.com/2006/mxml"; + public static string BETA_MX = "library://ns.adobe.com/flex/halo"; + public static string NEW_MX = "library://ns.adobe.com/flex/mx"; - static private List catalogs = new List(); - static private Dictionary archive = new Dictionary(); + static readonly List catalogs = new List(); + static readonly Dictionary archive = new Dictionary(); /// /// Reset catalogs for new classpath definition /// - static public void ClearCatalogs() - { - catalogs.Clear(); - } + public static void ClearCatalogs() => catalogs.Clear(); /// /// Look in current project configuration for user-defined namespaces /// - static public void AddProjectManifests() + public static void AddProjectManifests() { - AS3Project project = PluginBase.CurrentProject as AS3Project; - if (project != null) + var project = PluginBase.CurrentProject as AS3Project; + //-compiler.namespaces.namespace http://e4xu.googlecode.com run\manifest.xml + if (project?.CompilerOptions.Additional is null) return; + foreach (var line in project.CompilerOptions.Additional) { - //-compiler.namespaces.namespace http://e4xu.googlecode.com run\manifest.xml - if (project.CompilerOptions.Additional != null) - foreach (string line in project.CompilerOptions.Additional) - { - string temp = line.Trim(); - if (temp.StartsWithOrdinal("-compiler.namespaces.namespace") || temp.StartsWithOrdinal("-namespace")) - { - int p = temp.IndexOf(' '); - if (p < 0) p = temp.IndexOf('='); - if (p < 0) continue; - temp = temp.Substring(p + 1).Trim(); - p = temp.IndexOf(' '); - if (p < 0) p = temp.IndexOf(','); - if (p < 0) continue; - string uri = temp.Substring(0, p); - string path = temp.Substring(p + 1).Trim(); - if (path.StartsWith('\"')) path = path.Substring(1, path.Length - 2); - AddManifest(uri, PathHelper.ResolvePath(path, project.Directory)); - } - } + var temp = line.Trim(); + if (temp.StartsWithOrdinal("-compiler.namespaces.namespace") || temp.StartsWithOrdinal("-namespace")) + { + int p = temp.IndexOf(' '); + if (p < 0) p = temp.IndexOf('='); + if (p < 0) continue; + temp = temp.Substring(p + 1).Trim(); + p = temp.IndexOf(' '); + if (p < 0) p = temp.IndexOf(','); + if (p < 0) continue; + string uri = temp.Substring(0, p); + string path = temp.Substring(p + 1).Trim(); + if (path.StartsWith('\"')) path = path.Substring(1, path.Length - 2); + AddManifest(uri, PathHelper.ResolvePath(path, project.Directory)); + } } } /// /// Check if a catalog was already extracted from indicated SWC /// - static public bool HasCatalog(string file) - { - return archive.ContainsKey(file); - } + public static bool HasCatalog(string file) => archive.ContainsKey(file); /// /// Read a SWC catalog file /// - static public void AddCatalogs(string file, byte[] rawData) + public static void AddCatalogs(string file, byte[] rawData) { try { @@ -107,13 +98,13 @@ static public void AddCatalogs(string file, byte[] rawData) catalogs.AddRange(cat.Values); } catch (XmlException ex) { Console.WriteLine(ex.Message); } - catch (Exception) { } + catch { } } /// /// Add an archived SWC catalog /// - static public void AddCatalog(string file) + public static void AddCatalog(string file) { MxmlCatalogs cat = archive[file]; if (cat.Count > 0) @@ -125,7 +116,7 @@ static public void AddCatalog(string file) /// /// /// - static public void AddManifest(string uri, string file) + public static void AddManifest(string uri, string file) { try { @@ -150,7 +141,7 @@ static public void AddManifest(string uri, string file) catalogs.AddRange(cat.Values); } catch (XmlException ex) { Console.WriteLine(ex.Message); } - catch (Exception) { } + catch { } } /// @@ -159,7 +150,7 @@ static public void AddManifest(string uri, string file) /// /// /// - static public string FilterSource(string name, string src, MxmlFilterContext ctx) + public static string FilterSource(string name, string src, MxmlFilterContext ctx) { List as3ranges = ctx.as3ranges; MemberList mxmlMembers = ctx.mxmlMembers; @@ -209,7 +200,8 @@ static public string FilterSource(string name, string src, MxmlFilterContext ctx i += 3; continue; } - else if (src[i + 2] == '[' && src.Substring(i + 2, 7) == "[CDATA[") + + if (src[i + 2] == '[' && src.Substring(i + 2, 7) == "[CDATA[") { i += 8; skip = false; @@ -225,7 +217,7 @@ static public string FilterSource(string name, string src, MxmlFilterContext ctx if (firstNode && src[i + 1] != '?') { - int space = src.IndexOfAny(new char[] { ' ', '\n' }, i); + int space = src.IndexOfAny(new[] { ' ', '\n' }, i); string tag = GetXMLContextTag(src, space); if (tag != null && space > 0) { @@ -287,16 +279,16 @@ static public string FilterSource(string name, string src, MxmlFilterContext ctx return sb.ToString(); } - private static void ReadNamespaces(MxmlFilterContext ctx, string src, int i) + static void ReadNamespaces(MxmlFilterContext ctx, string src, int i) { // declared ns int len = src.Length; while (i < len) { string name = GetAttributeName(src, ref i); - if (name == null) break; + if (name is null) break; string value = GetAttributeValue(src, ref i); - if (value == null) break; + if (value is null) break; if (name.StartsWithOrdinal("xmlns")) { string[] qname = name.Split(':'); @@ -321,24 +313,24 @@ private static void ReadNamespaces(MxmlFilterContext ctx, string src, int i) /// /// Get the attribute name /// - private static string GetAttributeName(string src, ref int i) + static string GetAttributeName(string src, ref int i) { string name = ""; - char c; int oldPos = 0; int len = src.Length; bool skip = true; while (i < len) { - c = src[i++]; + var c = src[i++]; if (c == '>') return null; if (skip && c > 32) skip = false; if (c == '=') { if (!skip) return name; - else break; + break; } - else if (!skip && c > 32) name += c; + + if (!skip && c > 32) name += c; } i = oldPos; return null; @@ -347,21 +339,20 @@ private static string GetAttributeName(string src, ref int i) /// /// Get the attribute value /// - private static string GetAttributeValue(string src, ref int i) + static string GetAttributeValue(string src, ref int i) { string value = ""; - char c; int oldPos = i; int len = src.Length; bool skip = true; while (i < len) { - c = src[i++]; + var c = src[i++]; if (c == 10 || c == 13) break; if (c == '"') { if (!skip) return value; - else skip = false; + skip = false; } else if (!skip) value += c; } @@ -372,7 +363,7 @@ private static string GetAttributeValue(string src, ref int i) /// /// Gets the xml context tag /// - private static string GetXMLContextTag(string src, int position) + static string GetXMLContextTag(string src, int position) { if (position < 0) return null; StringBuilder sb = new StringBuilder(); @@ -390,7 +381,7 @@ private static string GetXMLContextTag(string src, int position) string tag = sb.ToString(); Match mTag = tagName.Match(tag + " "); if (mTag.Success) return mTag.Groups["name"].Value; - else return null; + return null; } /// @@ -399,13 +390,13 @@ private static string GetXMLContextTag(string src, int position) /// /// /// - static public void FilterSource(FileModel model, MxmlFilterContext ctx) + public static void FilterSource(FileModel model, MxmlFilterContext ctx) { ctx.model = model; model.InlinedIn = "xml"; model.InlinedRanges = ctx.as3ranges; - if (model.MetaDatas == null) model.MetaDatas = new List(); + model.MetaDatas ??= new List(); foreach (string key in ctx.namespaces.Keys) { ASMetaData meta = new ASMetaData("Namespace"); @@ -414,23 +405,23 @@ static public void FilterSource(FileModel model, MxmlFilterContext ctx) model.MetaDatas.Add(meta); } - ClassModel aClass = model.GetPublicClass(); + var aClass = model.GetPublicClass(); if (aClass == ClassModel.VoidClass) return; aClass.Comments = "<" + ctx.baseTag + "/>"; - Dictionary resolved = new Dictionary(); - foreach (MemberModel mxmember in ctx.mxmlMembers) + var resolved = new Dictionary(); + foreach (var mxmember in ctx.mxmlMembers) { - string tag = mxmember.Type; - string type = null; + var tag = mxmember.Type; + string type; if (resolved.ContainsKey(tag)) type = resolved[tag]; else { type = MxmlComplete.ResolveType(ctx, tag); resolved[tag] = type; } - MemberModel member = aClass.Members.Search(mxmember.Name, FlagType.Variable, Visibility.Public); + var member = aClass.Members.Search(mxmember.Name, FlagType.Variable, Visibility.Public); if (member != null) { member.Comments = "<" + tag + "/>"; @@ -442,41 +433,36 @@ static public void FilterSource(FileModel model, MxmlFilterContext ctx) #endregion #region Catalogs - class MxmlCatalogs : Dictionary + class MxmlCatalogs : Dictionary { - public String FileName; + public string FileName; public DateTime TimeStamp; - public void Read(string fileName, byte[] rawData) - { - Read(fileName, rawData, null); - } + public void Read(string fileName, byte[] rawData) => Read(fileName, rawData, null); public void Read(string fileName, byte[] rawData, string defaultURI) { FileName = fileName; - XmlReader reader; - if (rawData == null) reader = new XmlTextReader(fileName); - else reader = new XmlTextReader(new MemoryStream(rawData)); + using XmlReader reader = rawData is null + ? new XmlTextReader(fileName) + : new XmlTextReader(new MemoryStream(rawData)); MxmlCatalog cat = null; reader.MoveToContent(); while (reader.Read()) { - if (reader.NodeType == XmlNodeType.Element - && reader.Name == "component") + if (reader.NodeType == XmlNodeType.Element && reader.Name == "component") { - string className = reader.GetAttribute("className") ?? reader.GetAttribute("class"); - string name = reader.GetAttribute("name") ?? reader.GetAttribute("id"); - string uri = reader.GetAttribute("uri") ?? defaultURI; + var className = reader.GetAttribute("className") ?? reader.GetAttribute("class"); + var name = reader.GetAttribute("name") ?? reader.GetAttribute("id"); + var uri = reader.GetAttribute("uri") ?? defaultURI; if (uri == MxmlFilter.BETA_MX || uri == MxmlFilter.OLD_MX) uri = MxmlFilter.NEW_MX; - - if (cat == null || cat.URI != uri) + if (cat is null || cat.URI != uri) { if (ContainsKey(uri)) cat = this[uri]; - else { - cat = new MxmlCatalog(); - cat.URI = uri; + else + { + cat = new MxmlCatalog {URI = uri}; Add(uri, cat); } } diff --git a/External/Plugins/AS3Context/PluginMain.cs b/External/Plugins/AS3Context/PluginMain.cs index 54f099b91e..b4897f1ab9 100644 --- a/External/Plugins/AS3Context/PluginMain.cs +++ b/External/Plugins/AS3Context/PluginMain.cs @@ -24,83 +24,54 @@ namespace AS3Context { public class PluginMain : IPlugin, InstalledSDKOwner { - private String pluginName = "AS3Context"; - private String pluginGuid = "ccf2c534-db6b-4c58-b90e-cd0b837e61c4"; - private String pluginHelp = "www.flashdevelop.org/community/"; - private String pluginDesc = "ActionScript 3 context for the ASCompletion engine."; - private String pluginAuth = "FlashDevelop Team"; - static private AS3Settings settingObject; - private Context contextInstance; - private String settingFilename; - private bool inMXML; - private Image pluginIcon; - private ProfilerUI profilerUI; - private DockContent profilerPanel; - private ToolStripButton viewButton; + Context contextInstance; + string settingFilename; + bool inMXML; + Image pluginIcon; + ProfilerUI profilerUI; + DockContent profilerPanel; + ToolStripButton viewButton; #region Required Properties /// /// Api level of the plugin /// - public Int32 Api - { - get { return 1; } - } + public int Api => 1; /// /// Name of the plugin /// - public String Name - { - get { return this.pluginName; } - } + public string Name { get; } = nameof(AS3Context); /// /// GUID of the plugin /// - public String Guid - { - get { return this.pluginGuid; } - } + public string Guid { get; } = "ccf2c534-db6b-4c58-b90e-cd0b837e61c4"; /// /// Author of the plugin /// - public String Author - { - get { return this.pluginAuth; } - } + public string Author { get; } = "FlashDevelop Team"; /// /// Description of the plugin /// - public String Description - { - get { return this.pluginDesc; } - } + public string Description { get; set; } = "ActionScript 3 context for the ASCompletion engine."; /// /// Web address for help /// - public String Help - { - get { return this.pluginHelp; } - } + public string Help { get; } = "https://www.flashdevelop.org/community/"; /// /// Object that contains the settings /// [Browsable(false)] - Object IPlugin.Settings - { - get { return settingObject; } - } + object IPlugin.Settings => Settings; + + public static AS3Settings Settings { get; set; } - static public AS3Settings Settings - { - get { return settingObject; } - } #endregion #region Required Methods @@ -110,11 +81,11 @@ static public AS3Settings Settings /// public void Initialize() { - this.InitBasics(); - this.LoadSettings(); - this.CreatePanels(); - this.CreateMenuItems(); - this.AddEventHandlers(); + InitBasics(); + LoadSettings(); + CreatePanels(); + CreateMenuItems(); + AddEventHandlers(); } /// @@ -123,99 +94,85 @@ public void Initialize() public void Dispose() { FlexDebugger.Stop(); - if (profilerUI != null) profilerUI.Cleanup(); - this.SaveSettings(); + profilerUI?.Cleanup(); + SaveSettings(); } /// /// Handles the incoming events /// - public void HandleEvent(Object sender, NotifyEvent e, HandlingPriority priority) + public void HandleEvent(object sender, NotifyEvent e, HandlingPriority priority) { if (priority == HandlingPriority.Low) { switch (e.Type) { case EventType.ProcessArgs: - TextEvent te = e as TextEvent; - if (te.Value.IndexOfOrdinal("$(FlexSDK)") >= 0) + var te = (TextEvent) e; + if (te.Value.Contains("$(FlexSDK)")) { te.Value = te.Value.Replace("$(FlexSDK)", contextInstance.GetCompilerPath()); } break; case EventType.Command: - DataEvent de = e as DataEvent; - string action = de.Action; - if (action == "ProjectManager.Project") + var de = (DataEvent) e; + var action = de.Action; + switch (action) { - FlexShells.Instance.Stop(); // clear - } - else if (action == "ProjectManager.OpenVirtualFile") - { - if (PluginBase.CurrentProject != null && PluginBase.CurrentProject.Language == "as3") - e.Handled = OpenVirtualFileModel(de.Data as String); - } - else if (!settingObject.DisableFDB && action == "AS3Context.StartDebugger") - { - string workDir = (PluginBase.CurrentProject != null) - ? Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath) - : Environment.CurrentDirectory; - - string flexSdk = settingObject.GetDefaultSDK().Path; - - // if the default sdk is not defined ask for project sdk - if (String.IsNullOrEmpty(flexSdk)) - { - flexSdk = PluginBase.MainForm.ProcessArgString("$(CompilerPath)"); - } - e.Handled = FlexDebugger.Start(workDir, flexSdk, null); - } - else if (action == "AS3Context.StartProfiler") - { - if (profilerUI.AutoStart) profilerUI.StartProfiling(); + case "ProjectManager.Project": + FlexShells.Instance.Stop(); // clear + break; + case "ProjectManager.OpenVirtualFile": + if (PluginBase.CurrentProject?.Language == "as3") e.Handled = OpenVirtualFileModel((string) de.Data); + break; + case "AS3Context.StartDebugger" when !Settings.DisableFDB: + var workDir = PluginBase.CurrentProject != null + ? Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath) + : Environment.CurrentDirectory; + var flexSdk = Settings.GetDefaultSDK().Path; + // if the default sdk is not defined ask for project sdk + if (string.IsNullOrEmpty(flexSdk)) flexSdk = PluginBase.MainForm.ProcessArgString("$(CompilerPath)"); + e.Handled = FlexDebugger.Start(workDir, flexSdk, null); + break; + case "AS3Context.StartProfiler": + if (profilerUI.AutoStart) profilerUI.StartProfiling(); + break; } break; case EventType.Keys: if (inMXML) { - KeyEvent ke = e as KeyEvent; - if (ke.Value == PluginBase.MainForm.GetShortcutItemKeys("SearchMenu.GotoDeclaration")) + var ke = (KeyEvent) e; + if (ke.Value == PluginBase.MainForm.GetShortcutItemKeys("SearchMenu.GotoDeclaration") && MxmlComplete.GotoDeclaration()) { - if (MxmlComplete.GotoDeclaration()) - { - ke.Handled = true; - ke.ProcessKey = false; - } + ke.Handled = true; + ke.ProcessKey = false; } } break; } return; } - - else if (priority == HandlingPriority.Normal) + if (priority == HandlingPriority.Normal) { switch (e.Type) { case EventType.UIStarted: - contextInstance = new Context(settingObject); + contextInstance = new Context(Settings); ValidateSettings(); AddToolbarItems(); // Associate this context with AS3 language ASContext.RegisterLanguage(contextInstance, "as3"); ASContext.RegisterLanguage(contextInstance, "mxml"); break; - case EventType.FileSave: case EventType.FileSwitch: - if (contextInstance != null) contextInstance.OnFileOperation(e); - - if (PluginBase.MainForm.CurrentDocument.IsEditable) + contextInstance?.OnFileOperation(e); + if (PluginBase.MainForm.CurrentDocument is {FileName: { } fileName}) { - string ext = Path.GetExtension(PluginBase.MainForm.CurrentDocument.FileName); - inMXML = (ext.ToLower() == ".mxml"); + inMXML = Path.GetExtension(fileName).ToLower() == ".mxml"; MxmlComplete.IsDirty = true; } else inMXML = false; @@ -223,107 +180,90 @@ public void HandleEvent(Object sender, NotifyEvent e, HandlingPriority priority) } return; } - - else if (priority == HandlingPriority.High) + if (priority == HandlingPriority.High) { if (e.Type == EventType.Command) { - string action = (e as DataEvent).Action; + var action = ((DataEvent) e).Action; if (action == "ProjectManager.Project") { FlexDebugger.Stop(); - IProject project = PluginBase.CurrentProject; - viewButton.Enabled = project == null || project.Language == "as3" || project.Language == "haxe"; + var project = PluginBase.CurrentProject; + viewButton.Enabled = project is null || project.Language == "as3" || project.Language == "haxe"; } else if (action.StartsWithOrdinal("FlashViewer.")) { - if (action == "FlashViewer.Closed") + switch (action) { - FlexDebugger.Stop(); - } - else if (action == "FlashViewer.External" || action == "FlashViewer.Default" - || action == "FlashViewer.Popup" || action == "FlashViewer.Document") - { - if (PluginBase.CurrentProject != null - && PluginBase.CurrentProject.EnableInteractiveDebugger) - { - DataEvent de = new DataEvent(EventType.Command, "AS3Context.StartProfiler", null); - EventManager.DispatchEvent(this, de); - - if (PluginBase.CurrentProject.TraceEnabled) + case "FlashViewer.Closed": + FlexDebugger.Stop(); + break; + case "FlashViewer.External": + case "FlashViewer.Default": + case "FlashViewer.Popup": + case "FlashViewer.Document": + if (PluginBase.CurrentProject != null && PluginBase.CurrentProject.EnableInteractiveDebugger) { - de = new DataEvent(EventType.Command, "AS3Context.StartDebugger", (e as DataEvent).Data); + var de = new DataEvent(EventType.Command, "AS3Context.StartProfiler", null); EventManager.DispatchEvent(this, de); + if (PluginBase.CurrentProject.TraceEnabled) + { + de = new DataEvent(EventType.Command, "AS3Context.StartDebugger", ((DataEvent) e).Data); + EventManager.DispatchEvent(this, de); + } } - } + break; } } - else if (action == "FlashConnect") - { - ProfilerUI.HandleFlashConnect(sender, (e as DataEvent).Data); - } + else if (action == "FlashConnect") ProfilerUI.HandleFlashConnect(sender, ((DataEvent) e).Data); else if (inMXML) { - DataEvent de = e as DataEvent; - if (de.Action == "XMLCompletion.Element") - { - de.Handled = MxmlComplete.HandleElement(de.Data); - } - if (de.Action == "XMLCompletion.Namespace") - { - de.Handled = MxmlComplete.HandleNamespace(de.Data); - } - else if (de.Action == "XMLCompletion.CloseElement") - { - de.Handled = MxmlComplete.HandleElementClose(de.Data); - } - else if (de.Action == "XMLCompletion.Attribute") - { - de.Handled = MxmlComplete.HandleAttribute(de.Data); - } - else if (de.Action == "XMLCompletion.AttributeValue") + var de = (DataEvent) e; + de.Handled = de.Action switch { - de.Handled = MxmlComplete.HandleAttributeValue(de.Data); - } + "XMLCompletion.Element" => MxmlComplete.HandleElement(de.Data), + "XMLCompletion.Namespace" => MxmlComplete.HandleNamespace(de.Data), + "XMLCompletion.CloseElement" => MxmlComplete.HandleElementClose(de.Data), + "XMLCompletion.Attribute" => MxmlComplete.HandleAttribute(de.Data), + "XMLCompletion.AttributeValue" => MxmlComplete.HandleAttributeValue(de.Data), + _ => de.Handled + }; } } } } - private bool OpenVirtualFileModel(string virtualPath) + bool OpenVirtualFileModel(string virtualPath) { - int p = virtualPath.IndexOfOrdinal("::"); + var p = virtualPath.IndexOfOrdinal("::"); if (p < 0) return false; - string container = virtualPath.Substring(0, p); - string ext = Path.GetExtension(container).ToLower(); + var container = virtualPath.Substring(0, p); + var ext = Path.GetExtension(container).ToLower(); if (ext != ".swf" && ext != ".swc" && ext != ".ane") return false; if (!File.Exists(container)) return false; - string fileName = Path.Combine(container, virtualPath.Substring(p + 2).Replace('.', Path.DirectorySeparatorChar)); - PathModel path = new PathModel(container, contextInstance); - ContentParser parser = new ContentParser(path.Path); + var path = new PathModel(container, contextInstance); + var parser = new ContentParser(path.Path); parser.Run(); AbcConverter.Convert(parser, path, contextInstance); - if (path.HasFile(fileName)) + string fileName = Path.Combine(container, virtualPath.Substring(p + 2).Replace('.', Path.DirectorySeparatorChar)); + if (path.TryGetFile(fileName, out var model)) { - FileModel model = path.GetFile(fileName); ASComplete.OpenVirtualFile(model); return true; } int split = fileName.LastIndexOf(Path.DirectorySeparatorChar) + 1; fileName = fileName.Substring(0, split) + "package.as"; - if (path.HasFile(fileName)) + if (path.TryGetFile(fileName, out model)) { - FileModel model = path.GetFile(fileName); ASComplete.OpenVirtualFile(model); return true; } fileName = fileName.Substring(0, split) + "toplevel.as"; - if (path.HasFile(fileName)) + if (path.TryGetFile(fileName, out model)) { - FileModel model = path.GetFile(fileName); ASComplete.OpenVirtualFile(model); return true; } @@ -339,21 +279,20 @@ private bool OpenVirtualFileModel(string virtualPath) /// public void InitBasics() { - String dataPath = Path.Combine(PathHelper.DataDir, "AS3Context"); - if (!Directory.Exists(dataPath)) Directory.CreateDirectory(dataPath); - this.settingFilename = Path.Combine(dataPath, "Settings.fdb"); - this.pluginDesc = TextHelper.GetString("Info.Description"); - this.pluginIcon = PluginBase.MainForm.FindImage("123"); + var path = Path.Combine(PathHelper.DataDir, nameof(AS3Context)); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + settingFilename = Path.Combine(path, "Settings.fdb"); + Description = TextHelper.GetString("Info.Description"); + pluginIcon = PluginBase.MainForm.FindImage("123"); } /// /// Create dock panels /// - private void CreatePanels() + void CreatePanels() { - profilerUI = new ProfilerUI(); - profilerUI.Text = TextHelper.GetString("Title.Profiler"); - profilerPanel = PluginBase.MainForm.CreateDockablePanel(profilerUI, pluginGuid, pluginIcon, DockState.Hidden); + profilerUI = new ProfilerUI {Text = TextHelper.GetString("Title.Profiler")}; + profilerPanel = PluginBase.MainForm.CreateDockablePanel(profilerUI, Guid, pluginIcon, DockState.Hidden); profilerPanel.VisibleState = DockState.Float; profilerUI.PanelRef = profilerPanel; } @@ -361,12 +300,11 @@ private void CreatePanels() /// /// Create toolbar icons & menu items /// - private void CreateMenuItems() + void CreateMenuItems() { - ToolStripMenuItem menu = PluginBase.MainForm.FindMenuItem("ViewMenu") as ToolStripMenuItem; - if (menu == null) return; + if (!(PluginBase.MainForm.FindMenuItem("ViewMenu") is ToolStripMenuItem menu)) return; - ToolStripMenuItem viewItem = new ToolStripMenuItem(TextHelper.GetString("Label.ViewMenuItem"), pluginIcon, new EventHandler(OpenPanel)); + var viewItem = new ToolStripMenuItem(TextHelper.GetString("Label.ViewMenuItem"), pluginIcon, OpenPanel); PluginBase.MainForm.RegisterShortcutItem("ViewMenu.ShowProfiler", viewItem); menu.DropDownItems.Add(viewItem); @@ -380,10 +318,10 @@ private void CreateMenuItems() /// /// Insert toolbar item at right position /// - private void AddToolbarItems() + void AddToolbarItems() { ToolStripItem checkSyntax = null; - ToolStrip toolbar = PluginBase.MainForm.ToolStrip; + var toolbar = PluginBase.MainForm.ToolStrip; foreach (ToolStripItem item in toolbar.Items) { if (item.Name == "CheckSyntax") @@ -406,7 +344,7 @@ private void AddToolbarItems() /// public void OpenPanel(object sender, EventArgs e) { - if (sender is ToolStripButton && profilerPanel.Visible && profilerPanel.DockState.ToString().IndexOfOrdinal("AutoHide") < 0) + if (sender is ToolStripButton && profilerPanel.Visible && !profilerPanel.DockState.ToString().Contains("AutoHide")) { profilerPanel.Hide(); } @@ -428,54 +366,42 @@ public void AddEventHandlers() /// public void LoadSettings() { - settingObject = new AS3Settings(); - if (!File.Exists(this.settingFilename)) this.SaveSettings(); - else - { - Object obj = ObjectSerializer.Deserialize(this.settingFilename, settingObject); - settingObject = (AS3Settings)obj; - } - if (settingObject.AS3ClassPath == null) settingObject.AS3ClassPath = @"Library\AS3\intrinsic"; + Settings = new AS3Settings(); + if (!File.Exists(settingFilename)) SaveSettings(); + else Settings = ObjectSerializer.Deserialize(settingFilename, Settings); + Settings.AS3ClassPath ??= @"Library\AS3\intrinsic"; } /// /// Fix some settings values when the context has been created /// - private void ValidateSettings() + void ValidateSettings() { - if (settingObject.InstalledSDKs == null || settingObject.InstalledSDKs.Length == 0 || PluginBase.MainForm.RefreshConfig) + if (Settings.InstalledSDKs.IsNullOrEmpty() || PluginBase.MainForm.RefreshConfig) { - InstalledSDK sdk; - List sdks = new List(); - string includedSDK; - includedSDK = "Tools\\flexsdk"; + var sdks = new List(); + var includedSDK = "Tools\\flexsdk"; if (Directory.Exists(PathHelper.ResolvePath(includedSDK))) { InstalledSDKContext.Current = this; - sdk = new InstalledSDK(this); - sdk.Path = includedSDK; - sdks.Add(sdk); + sdks.Add(new InstalledSDK(this) {Path = includedSDK}); } includedSDK = "Tools\\ascsdk"; if (Directory.Exists(PathHelper.ResolvePath(includedSDK))) { InstalledSDKContext.Current = this; - sdk = new InstalledSDK(this); - sdk.Path = includedSDK; - sdks.Add(sdk); + sdks.Add(new InstalledSDK(this) {Path = includedSDK}); } /* Resolve AppMan Flex SDKs */ - string appManDir = Path.Combine(PathHelper.BaseDir, @"Apps\flexsdk"); + var appManDir = Path.Combine(PathHelper.BaseDir, @"Apps\flexsdk"); if (Directory.Exists(appManDir)) { - string[] versionDirs = Directory.GetDirectories(appManDir); - foreach (string versionDir in versionDirs) + var versionDirs = Directory.GetDirectories(appManDir); + foreach (var versionDir in versionDirs) { if (Directory.Exists(versionDir)) { - sdk = new InstalledSDK(this); - sdk.Path = versionDir; - sdks.Add(sdk); + sdks.Add(new InstalledSDK(this) {Path = versionDir}); } } } @@ -483,14 +409,12 @@ private void ValidateSettings() appManDir = Path.Combine(PathHelper.BaseDir, @"Apps\flexairsdk"); if (Directory.Exists(appManDir)) { - string[] versionDirs = Directory.GetDirectories(appManDir); - foreach (string versionDir in versionDirs) + var versionDirs = Directory.GetDirectories(appManDir); + foreach (var versionDir in versionDirs) { if (Directory.Exists(versionDir)) { - sdk = new InstalledSDK(this); - sdk.Path = versionDir; - sdks.Add(sdk); + sdks.Add(new InstalledSDK(this) {Path = versionDir}); } } } @@ -498,29 +422,27 @@ private void ValidateSettings() appManDir = Path.Combine(PathHelper.BaseDir, @"Apps\ascsdk"); if (Directory.Exists(appManDir)) { - string[] versionDirs = Directory.GetDirectories(appManDir); - foreach (string versionDir in versionDirs) + var versionDirs = Directory.GetDirectories(appManDir); + foreach (var versionDir in versionDirs) { if (Directory.Exists(versionDir)) { - sdk = new InstalledSDK(this); - sdk.Path = versionDir; - sdks.Add(sdk); + sdks.Add(new InstalledSDK(this) {Path = versionDir}); } } } // // TODO: Resolve Apache Flex SDK // - if (settingObject.InstalledSDKs != null) + if (Settings.InstalledSDKs != null) { - char[] slashes = new char[] { '/', '\\' }; - foreach (InstalledSDK oldSdk in settingObject.InstalledSDKs) + char[] slashes = { '/', '\\' }; + foreach (var oldSdk in Settings.InstalledSDKs) { - string oldPath = oldSdk.Path.TrimEnd(slashes); - foreach (InstalledSDK newSdk in sdks) + var oldPath = oldSdk.Path.TrimEnd(slashes); + foreach (var newSdk in sdks) { - string newPath = newSdk.Path.TrimEnd(slashes); + var newPath = newSdk.Path.TrimEnd(slashes); if (newPath.Equals(oldPath, StringComparison.OrdinalIgnoreCase)) { sdks.Remove(newSdk); @@ -528,67 +450,59 @@ private void ValidateSettings() } } } - sdks.InsertRange(0, settingObject.InstalledSDKs); + sdks.InsertRange(0, Settings.InstalledSDKs); } - settingObject.InstalledSDKs = sdks.ToArray(); + Settings.InstalledSDKs = sdks.ToArray(); } else { - foreach (InstalledSDK sdk in settingObject.InstalledSDKs) + foreach (var sdk in Settings.InstalledSDKs) { sdk.Validate(); } } - settingObject.OnClasspathChanged += SettingObjectOnClasspathChanged; - settingObject.OnInstalledSDKsChanged += settingObjectOnInstalledSDKsChanged; + Settings.OnClasspathChanged += SettingObjectOnClasspathChanged; + Settings.OnInstalledSDKsChanged += SettingObjectOnInstalledSDKsChanged; } /// /// Notify of SDK collection changes /// - void settingObjectOnInstalledSDKsChanged() + void SettingObjectOnInstalledSDKsChanged() { - if (contextInstance != null) - { - DataEvent de = new DataEvent(EventType.Command, "ProjectManager.InstalledSDKsChanged", "as3"); - EventManager.DispatchEvent(contextInstance, de); - if (!de.Handled) contextInstance.BuildClassPath(); - } + if (contextInstance is null) return; + var de = new DataEvent(EventType.Command, "ProjectManager.InstalledSDKsChanged", "as3"); + EventManager.DispatchEvent(contextInstance, de); + if (!de.Handled) contextInstance.BuildClassPath(); } /// /// Update the classpath if an important setting has changed /// - private void SettingObjectOnClasspathChanged() - { - if (contextInstance != null) contextInstance.BuildClassPath(); - } + void SettingObjectOnClasspathChanged() => contextInstance?.BuildClassPath(); /// /// Saves the plugin settings /// - public void SaveSettings() - { - ObjectSerializer.Serialize(this.settingFilename, settingObject); - } + public void SaveSettings() => ObjectSerializer.Serialize(settingFilename, Settings); /// /// Explore the possible locations for the Macromedia Flash IDE classpath /// - static public string FindAuthoringConfigurationPath(string flashPath) + public static string FindAuthoringConfigurationPath(string flashPath) { - if (flashPath == null) + if (flashPath is null) { flashPath = CallFlashIDE.FindFlashIDE(true); - if (flashPath == null) return null; + if (flashPath is null) return null; } - string ext = Path.GetExtension(flashPath).ToLower(); + var ext = Path.GetExtension(flashPath).ToLower(); if (ext == ".exe" || ext == ".bat" || ext == ".cmd") { flashPath = Path.GetDirectoryName(flashPath); } - string basePath = flashPath; - string deflang = CultureInfo.CurrentUICulture.Name; + var basePath = flashPath; + var deflang = CultureInfo.CurrentUICulture.Name; deflang = deflang.Substring(0, 2); // CS4+ default configuration if (Directory.Exists(basePath + "\\Common\\Configuration\\ActionScript 3.0")) @@ -601,10 +515,10 @@ static public string FindAuthoringConfigurationPath(string flashPath) return basePath + deflang + "\\Configuration\\"; } // look for other languages - else if (Directory.Exists(basePath)) + if (Directory.Exists(basePath)) { - string[] dirs = Directory.GetDirectories(basePath); - foreach (string dir in dirs) + var dirs = Directory.GetDirectories(basePath); + foreach (var dir in dirs) { if (Directory.Exists(dir + "\\Configuration\\ActionScript 3.0")) { @@ -622,21 +536,19 @@ static public string FindAuthoringConfigurationPath(string flashPath) public bool ValidateSDK(InstalledSDK sdk) { sdk.Owner = this; - string path = sdk.Path; - if (path == null) return false; - Match mBin = Regex.Match(path, "[/\\\\]bin$", RegexOptions.IgnoreCase); - if (mBin.Success) - sdk.Path = path = path.Substring(0, mBin.Index); - - IProject project = PluginBase.CurrentProject; - if (project != null) - path = PathHelper.ResolvePath(path, Path.GetDirectoryName(project.ProjectPath)); - else - path = PathHelper.ResolvePath(path); + var path = sdk.Path; + if (path is null) return false; + var mBin = Regex.Match(path, "[/\\\\]bin$", RegexOptions.IgnoreCase); + if (mBin.Success) sdk.Path = path = path.Substring(0, mBin.Index); + + var project = PluginBase.CurrentProject; + path = project != null + ? PathHelper.ResolvePath(path, Path.GetDirectoryName(project.ProjectPath)) + : PathHelper.ResolvePath(path); try { - if (path == null || !Directory.Exists(path)) + if (!Directory.Exists(path)) { ErrorManager.ShowInfo("Path not found:\n" + sdk.Path); return false; @@ -648,15 +560,13 @@ public bool ValidateSDK(InstalledSDK sdk) return false; } - string descriptor = Path.Combine(path, "flex-sdk-description.xml"); - if (!File.Exists(descriptor)) - descriptor = Path.Combine(path, "air-sdk-description.xml"); - + var descriptor = Path.Combine(path, "flex-sdk-description.xml"); + if (!File.Exists(descriptor)) descriptor = Path.Combine(path, "air-sdk-description.xml"); if (File.Exists(descriptor)) { - string raw = File.ReadAllText(descriptor); - Match mName = Regex.Match(raw, "([^<]+)"); - Match mVer = Regex.Match(raw, "([^<]+)"); + var raw = File.ReadAllText(descriptor); + var mName = Regex.Match(raw, "([^<]+)"); + var mVer = Regex.Match(raw, "([^<]+)"); if (mName.Success && mVer.Success) { sdk.Name = mName.Groups[1].Value; @@ -666,7 +576,7 @@ public bool ValidateSDK(InstalledSDK sdk) if (sdk.Name.StartsWithOrdinal("Flex") && File.Exists(descriptor)) { raw = File.ReadAllText(descriptor); - Match mAIR = Regex.Match(raw, "Adobe AIR ([0-9.]+) SDK"); + var mAIR = Regex.Match(raw, "Adobe AIR ([0-9.]+) SDK"); if (mAIR.Success) { sdk.Name += ", AIR " + mAIR.Groups[1].Value; @@ -675,14 +585,12 @@ public bool ValidateSDK(InstalledSDK sdk) } return true; } - else ErrorManager.ShowInfo("Invalid SDK descriptor:\n" + descriptor); + ErrorManager.ShowInfo("Invalid SDK descriptor:\n" + descriptor); } else ErrorManager.ShowInfo("No SDK descriptor found:\n" + descriptor); return false; } #endregion - } - -} +} \ No newline at end of file diff --git a/External/Plugins/AS3Context/Properties/AssemblyInfo.cs b/External/Plugins/AS3Context/Properties/AssemblyInfo.cs index 45eeec97ff..e33473e0bb 100644 --- a/External/Plugins/AS3Context/Properties/AssemblyInfo.cs +++ b/External/Plugins/AS3Context/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using PluginCore; // Information about this assembly is defined by the following attributes. @@ -12,3 +13,5 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: AssemblyVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("AS3Context.Tests")] diff --git a/External/Plugins/ASClassWizard/ASClassWizard.csproj b/External/Plugins/ASClassWizard/ASClassWizard.csproj index 7f3571f4a6..94878b73cc 100644 --- a/External/Plugins/ASClassWizard/ASClassWizard.csproj +++ b/External/Plugins/ASClassWizard/ASClassWizard.csproj @@ -1,151 +1,90 @@  - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {A2C159C1-7D21-4483-AEB1-38D9FDC4C7F3} - Library - Properties - ASClassWizard - ASClassWizard - - - - - 3.5 - v4.0 - - - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - DEBUG;TRACE - prompt - 4 - - - none - true - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - prompt - 4 - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - true - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - true - - - - - - - - - - - - - - - Form - - - AS3ClassWizard.cs - - - Form - - - ClassBrowser.cs - - - Component - - - Form - - - PackageBrowser.cs - - - - - {61885F70-B4DC-4B44-852D-5D6D03F2A734} - PluginCore - False - - - {4EBF2653-9654-4E40-880E-0046B3D6210E} - ASCompletion - False - - - {78101C01-E186-4954-B1DD-DEBB7905FAD8} - ProjectManager - False - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - - + + + + Debug + AnyCPU + {A2C159C1-7D21-4483-AEB1-38D9FDC4C7F3} + Library + Properties + ASClassWizard + ASClassWizard + net48 + true + false + false + false + + + true + full + false + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + prompt + 4 + 9 + + + none + true + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + prompt + 4 + 9 + + + x86 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + true + 9 + + + x86 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + true + 9 + + + true + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + full + x64 + 9 + prompt + + + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + true + x64 + 9 + prompt + + + + + + + + + {61885F70-B4DC-4B44-852D-5D6D03F2A734} + PluginCore + False + + + {4EBF2653-9654-4E40-880E-0046B3D6210E} + ASCompletion + False + + + {78101C01-E186-4954-B1DD-DEBB7905FAD8} + ProjectManager + False + + \ No newline at end of file diff --git a/External/Plugins/ASClassWizard/Controls/TreeView/SimpleDirectoryNode.cs b/External/Plugins/ASClassWizard/Controls/TreeView/SimpleDirectoryNode.cs index 181fab892e..4505508cb9 100644 --- a/External/Plugins/ASClassWizard/Controls/TreeView/SimpleDirectoryNode.cs +++ b/External/Plugins/ASClassWizard/Controls/TreeView/SimpleDirectoryNode.cs @@ -11,11 +11,11 @@ class SimpleDirectoryNode : TreeNode public SimpleDirectoryNode(string directory, string path) : base(Path.GetFileName(directory)) { - this.dirty = true; - this.directoryPath = path; + dirty = true; + directoryPath = path; if (Directory.GetDirectories(path).Length > 0) - this.Nodes.Add(new TreeNode("")); + Nodes.Add(new TreeNode("")); } } } diff --git a/External/Plugins/ASClassWizard/PluginMain.cs b/External/Plugins/ASClassWizard/PluginMain.cs index ff7417e058..85e684204a 100644 --- a/External/Plugins/ASClassWizard/PluginMain.cs +++ b/External/Plugins/ASClassWizard/PluginMain.cs @@ -1,105 +1,66 @@ using System; using System.IO; -using System.Windows.Forms; using System.ComponentModel; using System.Collections; using PluginCore.Localization; -using PluginCore.Utilities; using PluginCore.Managers; using PluginCore; using ProjectManager.Projects; -using ASCompletion.Model; using ASCompletion.Context; -using ASClassWizard.Resources; -using ASClassWizard.Wizards; using ASCompletion.Completion; using System.Collections.Generic; -using System.Linq; +using ASClassWizard.Wizards; namespace ASClassWizard { public class PluginMain : IPlugin { - private String pluginName = "ASClassWizard"; - private String pluginGuid = "a2c159c1-7d21-4483-aeb1-38d9fdc4c7f3"; - private String pluginHelp = "www.flashdevelop.org/community/"; - private String pluginDesc = "Provides an ActionScript class wizard for FlashDevelop."; - private String pluginAuth = "FlashDevelop Team"; - - private AS3ClassOptions lastFileOptions; - private String lastFileFromTemplate; - private IASContext processContext; - private String processOnSwitch; - private String constructorArgs; - private List constructorArgTypes; - #region Required Properties /// /// Api level of the plugin /// - public Int32 Api - { - get { return 1; } - } + public int Api => 1; /// /// Name of the plugin /// - public String Name - { - get { return this.pluginName; } - } + public string Name => nameof(ASClassWizard); /// /// GUID of the plugin /// - public String Guid - { - get { return this.pluginGuid; } - } + public string Guid => "a2c159c1-7d21-4483-aeb1-38d9fdc4c7f3"; /// /// Author of the plugin /// - public String Author - { - get { return this.pluginAuth; } - } + public string Author => "FlashDevelop Team"; /// /// Description of the plugin /// - public String Description - { - get { return this.pluginDesc; } - } + public string Description { get; private set; } = "Provides an ActionScript class wizard for FlashDevelop."; /// /// Web address for help /// - public String Help - { - get { return this.pluginHelp; } - } + public string Help => "https://www.flashdevelop.org/community/"; /// /// Object that contains the settings /// [Browsable(false)] - public Object Settings - { - get { return null; } - } - + public object Settings => null; + #endregion #region Required Methods public void Initialize() { - this.AddEventHandlers(); - this.InitLocalization(); + AddEventHandlers(); + InitLocalization(); } public void Dispose() @@ -107,373 +68,91 @@ public void Dispose() // Nothing here... } - public void HandleEvent(Object sender, NotifyEvent e, HandlingPriority priority) + public void HandleEvent(object sender, NotifyEvent e, HandlingPriority priority) { Project project; switch (e.Type) { case EventType.Command: - DataEvent evt = (DataEvent)e; - if (evt.Action == "ProjectManager.CreateNewFile") + var de = (DataEvent)e; + if (de.Action == "ProjectManager.CreateNewFile") { - Hashtable table = evt.Data as Hashtable; - project = PluginBase.CurrentProject as Project; - if ((project.Language.StartsWithOrdinal("as") || project.Language == "haxe") && IsWizardTemplate(table["templatePath"] as String)) + project = (Project) PluginBase.CurrentProject; + if (project.Language.StartsWithOrdinal("as") || project.Language == "haxe") { - evt.Handled = true; - String className = table.ContainsKey("className") ? table["className"] as String : TextHelper.GetString("Wizard.Label.NewClass"); - DisplayClassWizard(table["inDirectory"] as String, table["templatePath"] as String, className, table["constructorArgs"] as String, table["constructorArgTypes"] as List); + var table = (Hashtable) de.Data; + var templateFile = table["templatePath"] as string; + if (WizardContext.IsWizardTemplate(templateFile)) + { + var fileName = Path.GetFileName(templateFile); + var templateType = !string.IsNullOrEmpty(fileName) && fileName.Contains('.', out var p) + ? fileName.Substring(0, p) + : "class"; + if (templateType.Equals("class", StringComparison.OrdinalIgnoreCase)) + { + de.Handled = true; + var inDirectory = (string)table["inDirectory"]; + var typeTemplate = table["GenericTemplate"] as string; + var name = table["className"] as string ?? TextHelper.GetString("Wizard.Label.NewClass"); + var constructorArgs = table["constructorArgs"] as string; + var constructorArgsTypes = table["constructorArgTypes"] as List; + using var dialog = new AS3ClassWizard(); + WizardContext.DisplayWizard(dialog, inDirectory, templateFile, typeTemplate, name, constructorArgs, constructorArgsTypes); + } + else if (templateType.Equals("interface", StringComparison.OrdinalIgnoreCase)) + { + de.Handled = true; + var inDirectory = (string) table["inDirectory"]; + var typeTemplate = table["GenericTemplate"] as string; + var name = table["interfaceName"] as string ?? TextHelper.GetString("Wizard.Label.NewInterface"); + using var dialog = new AS3InterfaceWizard(); + WizardContext.DisplayWizard(dialog, inDirectory, templateFile, typeTemplate, name, null, null); + } + } } } break; case EventType.FileSwitch: - if (PluginBase.MainForm.CurrentDocument.FileName == processOnSwitch) + if (PluginBase.MainForm.CurrentDocument?.FileName == WizardContext.processOnSwitch) { - processOnSwitch = null; - if (lastFileOptions == null || lastFileOptions.interfaces == null) return; - foreach (String cname in lastFileOptions.interfaces) + WizardContext.processOnSwitch = null; + if (WizardContext.lastFileOptions?.interfaces is null) return; + foreach (var it in WizardContext.lastFileOptions.interfaces) { ASContext.Context.CurrentModel.Check(); - ClassModel inClass = ASContext.Context.CurrentModel.GetPublicClass(); - ASGenerator.SetJobContext(null, cname, null, null); + var inClass = ASContext.Context.CurrentModel.GetPublicClass(); + ASGenerator.SetJobContext(null, it, null, null); ASGenerator.GenerateJob(GeneratorJobType.ImplementInterface, null, inClass, null, null); + ASContext.Context.UpdateCurrentFile(false); } - lastFileOptions = null; + WizardContext.lastFileOptions = null; } break; case EventType.ProcessArgs: - TextEvent te = e as TextEvent; project = PluginBase.CurrentProject as Project; - if (lastFileFromTemplate != null && project != null && (project.Language.StartsWithOrdinal("as") || project.Language == "haxe")) + if (WizardContext.lastFileFromTemplate != null && project != null && (project.Language.StartsWithOrdinal("as") || project.Language == "haxe")) { - te.Value = ProcessArgs(project, te.Value); + var te = (TextEvent) e; + te.Value = WizardContext.ProcessArgs(te.Value); } break; } } - private bool IsWizardTemplate(string templateFile) - { - return templateFile != null && File.Exists(templateFile + ".wizard"); - } - #endregion #region Custom Methods - public static IMainForm MainForm { get { return PluginBase.MainForm; } } - - public void AddEventHandlers() + void AddEventHandlers() { EventManager.AddEventHandler(this, EventType.Command | EventType.ProcessArgs); EventManager.AddEventHandler(this, EventType.FileSwitch, HandlingPriority.Low); } - public void InitLocalization() - { - this.pluginDesc = TextHelper.GetString("Info.Description"); - } - - private void DisplayClassWizard(String inDirectory, String templateFile, String className, String constructorArgs, List constructorArgTypes) - { - Project project = PluginBase.CurrentProject as Project; - String classpath = project.AbsoluteClasspaths.GetClosestParent(inDirectory) ?? inDirectory; - String package; - try - { - package = GetPackage(classpath, inDirectory); - if (package == "") - { - // search in Global classpath - Hashtable info = new Hashtable(); - info["language"] = project.Language; - DataEvent de = new DataEvent(EventType.Command, "ASCompletion.GetUserClasspath", info); - EventManager.DispatchEvent(this, de); - if (de.Handled && info.ContainsKey("cp")) - { - List cps = info["cp"] as List; - if (cps != null) - { - foreach (string cp in cps) - { - package = GetPackage(cp, inDirectory); - if (package != "") - { - classpath = cp; - break; - } - } - } - } - } - } - catch (System.NullReferenceException) - { - package = ""; - } - using (AS3ClassWizard dialog = new AS3ClassWizard()) - { - bool isHaxe = project.Language == "haxe"; - dialog.Project = project; - dialog.Directory = inDirectory; - dialog.StartupClassName = className; - if (package != null) - { - package = package.Replace(Path.DirectorySeparatorChar, '.'); - dialog.StartupPackage = package; - } - DialogResult conflictResult = DialogResult.OK; - string cPackage, path, newFilePath; - do - { - if (dialog.ShowDialog() != DialogResult.OK) return; - cPackage = dialog.getPackage(); - path = Path.Combine(classpath, cPackage.Replace('.', Path.DirectorySeparatorChar)); - newFilePath = Path.ChangeExtension(Path.Combine(path, dialog.getClassName()), - isHaxe ? ".hx" : ".as"); - if (File.Exists(newFilePath)) - { - string title = " " + TextHelper.GetString("FlashDevelop.Title.ConfirmDialog"); - string message = TextHelper.GetString("PluginCore.Info.FolderAlreadyContainsFile"); - conflictResult = MessageBox.Show(PluginBase.MainForm, - string.Format(message, newFilePath, "\n"), title, - MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); - if (conflictResult == DialogResult.No) return; - } - } while (conflictResult == DialogResult.Cancel); - - string templatePath = templateFile + ".wizard"; - this.lastFileFromTemplate = newFilePath; - this.constructorArgs = constructorArgs; - this.constructorArgTypes = constructorArgTypes; - lastFileOptions = new AS3ClassOptions( - project.Language, - dialog.getPackage(), - dialog.getSuperClass(), - dialog.hasInterfaces() ? dialog.getInterfaces() : null, - dialog.isPublic(), - dialog.isDynamic(), - dialog.isFinal(), - dialog.getGenerateInheritedMethods(), - dialog.getGenerateConstructor() - ); - - try - { - if (!Directory.Exists(path)) Directory.CreateDirectory(path); - MainForm.FileFromTemplate(templatePath, newFilePath); - } - catch (Exception ex) - { - ErrorManager.ShowError(ex); - } - } - } - - private string GetPackage(string classpath, string path) - { - if (!path.StartsWith(classpath, StringComparison.OrdinalIgnoreCase)) - return ""; - string subPath = path.Substring(classpath.Length).Trim(new char[] { '/', '\\', ' ', '.' }); - return subPath.Replace(Path.DirectorySeparatorChar, '.'); - } - - public string ProcessArgs(Project project, string args) - { - if (lastFileFromTemplate != null) - { - string package = lastFileOptions != null ? lastFileOptions.Package : ""; - string fileName = Path.GetFileNameWithoutExtension(lastFileFromTemplate); - args = args.Replace("$(FileName)", fileName); - if (args.Contains("$(FileNameWithPackage)") || args.Contains("$(Package)")) - { - if (package == "") args = args.Replace(" $(Package)", ""); - args = args.Replace("$(Package)", package); - if (package != "") args = args.Replace("$(FileNameWithPackage)", package + "." + fileName); - else args = args.Replace("$(FileNameWithPackage)", fileName); - if (lastFileOptions != null) - { - args = ProcessFileTemplate(args); - if (processOnSwitch == null) lastFileOptions = null; - } - } - lastFileFromTemplate = null; - } - return args; - } - - private string ProcessFileTemplate(string args) - { - Int32 eolMode = (Int32)MainForm.Settings.EOLMode; - String lineBreak = LineEndDetector.GetNewLineMarker(eolMode); - List imports = new List(); - string extends = ""; - string implements = ""; - string access = ""; - string inheritedMethods = ""; - string paramString = ""; - string superConstructor = ""; - string classMetadata = ""; - int index; - // resolve imports - if (lastFileOptions.interfaces != null && lastFileOptions.interfaces.Count > 0) - { - string implementContinuation; - implements = " implements "; - index = 0; - - if (lastFileOptions.Language == "haxe") - { - bool isHaxe2 = PluginBase.CurrentSDK != null && PluginBase.CurrentSDK.Name.ToLower().Contains("haxe 2"); - implementContinuation = isHaxe2 ? ", implements " : " implements "; - } - else - { - implementContinuation = ", "; - } - - foreach (string item in lastFileOptions.interfaces) - { - if (item.Contains('.')) imports.Add(item); - implements += (index > 0 ? implementContinuation : "") + item.Split('.').Last(); - if (lastFileOptions.createInheritedMethods) - { - processOnSwitch = lastFileFromTemplate; - // let ASCompletion generate the implementations when file is opened - } - index++; - } - } - if (lastFileOptions.superClass != "") - { - var superClassFullName = lastFileOptions.superClass; - if (superClassFullName.Contains(".")) imports.Add(superClassFullName); - var superClassShortName = superClassFullName.Split('.').Last(); - var fileName = Path.GetFileNameWithoutExtension(lastFileFromTemplate); - extends = fileName == superClassShortName ? $" extends {superClassFullName}" : $" extends {superClassShortName}"; - processContext = ASContext.GetLanguageContext(lastFileOptions.Language); - if (lastFileOptions.createConstructor && processContext != null && constructorArgs == null) - { - var lastDotIndex = superClassFullName.LastIndexOf('.'); - var cmodel = processContext.GetModel(lastDotIndex < 0 ? "" : superClassFullName.Substring(0, lastDotIndex), superClassShortName, ""); - if (!cmodel.IsVoid()) - { - if ((cmodel.Flags & FlagType.TypeDef) != 0) - { - var tmp = cmodel; - while (!tmp.IsVoid()) - { - if (!string.IsNullOrEmpty(tmp.Constructor)) - { - cmodel = tmp; - break; - } - tmp.ResolveExtends(); - tmp = tmp.Extends; - } - } - foreach (MemberModel member in cmodel.Members) - { - if (member.Name == cmodel.Constructor) - { - paramString = member.ParametersString(); - AddImports(imports, member, cmodel); - superConstructor = "super("; - index = 0; - if (member.Parameters != null) - foreach (MemberModel param in member.Parameters) - { - if (param.Name.StartsWith('.')) break; - var pname = TemplateUtils.GetParamName(param); - superConstructor += (index > 0 ? ", " : "") + pname; - index++; - } - superConstructor += ");\n" + (lastFileOptions.Language == "as3" ? "\t\t\t" : "\t\t"); - break; - } - } - } - } - processContext = null; - } - if (constructorArgs != null) - { - paramString = constructorArgs; - foreach (String type in constructorArgTypes) - { - if (!imports.Contains(type)) - { - imports.Add(type); - } - } - } - if (lastFileOptions.Language == "as3") - { - access = lastFileOptions.isPublic ? "public " : "internal "; - access += lastFileOptions.isDynamic ? "dynamic " : ""; - access += lastFileOptions.isFinal ? "final " : ""; - } - else if (lastFileOptions.Language == "haxe") - { - access = lastFileOptions.isPublic ? "public " : "private "; - access += lastFileOptions.isDynamic ? "dynamic " : ""; - if (lastFileOptions.isFinal) classMetadata += "@:final\n"; - } - else - { - access = lastFileOptions.isDynamic ? "dynamic " : ""; - } - string importsSrc = ""; - string prevImport = null; - imports.Sort(); - foreach (string import in imports) - { - if (prevImport != import) - { - prevImport = import; - if (import.LastIndexOf('.') == -1) continue; - if (import.Substring(0, import.LastIndexOf('.')) == lastFileOptions.Package) continue; - importsSrc += (lastFileOptions.Language == "as3" ? "\t" : "") + "import " + import + ";" + lineBreak; - } - } - if (importsSrc.Length > 0) - { - importsSrc += (lastFileOptions.Language == "as3" ? "\t" : "") + lineBreak; - } - args = args.Replace("$(Import)", importsSrc); - args = args.Replace("$(Extends)", extends); - args = args.Replace("$(Implements)", implements); - args = args.Replace("$(Access)", access); - args = args.Replace("$(InheritedMethods)", inheritedMethods); - args = args.Replace("$(ConstructorArguments)", paramString); - args = args.Replace("$(Super)", superConstructor); - args = args.Replace("$(ClassMetadata)", classMetadata); - return args; - } - - private void AddImports(List imports, MemberModel member, ClassModel inClass) - { - AddImport(imports, member.Type, inClass); - if (member.Parameters != null) - { - foreach (MemberModel item in member.Parameters) - { - AddImport(imports, item.Type, inClass); - } - } - } - - private void AddImport(List imports, String cname, ClassModel inClass) - { - ClassModel aClass = processContext.ResolveType(cname, inClass.InFile); - if (aClass != null && !aClass.IsVoid() && aClass.InFile.Package != "") - { - imports.Add(aClass.QualifiedName); - } - } + void InitLocalization() => Description = TextHelper.GetString("Info.Description"); #endregion } -} +} \ No newline at end of file diff --git a/External/Plugins/ASClassWizard/Resources/ASClassOptions.cs b/External/Plugins/ASClassWizard/Resources/ASClassOptions.cs index cea8cb0262..cb82bbe9ee 100644 --- a/External/Plugins/ASClassWizard/Resources/ASClassOptions.cs +++ b/External/Plugins/ASClassWizard/Resources/ASClassOptions.cs @@ -13,6 +13,8 @@ public class AS3ClassOptions public bool isDynamic; public bool isFinal; public string Language; + // TODO slavara: move to HaxeClassOptions + public string Template; public AS3ClassOptions( string language, diff --git a/External/Plugins/ASClassWizard/Settings.cs b/External/Plugins/ASClassWizard/Settings.cs index 33760a8774..5a8c4707c2 100644 --- a/External/Plugins/ASClassWizard/Settings.cs +++ b/External/Plugins/ASClassWizard/Settings.cs @@ -1,8 +1,4 @@ using System; -using System.ComponentModel; -using System.Collections.Generic; -using System.Windows.Forms; -using System.Text; namespace ASClassWizard { @@ -10,5 +6,4 @@ namespace ASClassWizard public class Settings { } - -} +} \ No newline at end of file diff --git a/External/Plugins/ASClassWizard/WizardContext.cs b/External/Plugins/ASClassWizard/WizardContext.cs new file mode 100644 index 0000000000..097efdc946 --- /dev/null +++ b/External/Plugins/ASClassWizard/WizardContext.cs @@ -0,0 +1,322 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using ASClassWizard.Resources; +using ASClassWizard.Wizards; +using ASCompletion.Completion; +using ASCompletion.Context; +using ASCompletion.Model; +using PluginCore; +using PluginCore.Localization; +using PluginCore.Managers; +using PluginCore.Utilities; +using ProjectManager.Projects; + +namespace ASClassWizard +{ + public static class WizardContext + { + + internal static AS3ClassOptions lastFileOptions; + internal static string lastFileFromTemplate; + internal static string processOnSwitch; + internal static string constructorArgs; + internal static List constructorArgTypes; + + public static bool IsWizardTemplate(string templateFile) => templateFile != null && File.Exists(templateFile + ".wizard"); + + public static void DisplayWizard(IWizard dialog, string inDirectory, string templateFile, string typeTemplate, string name, string constructorArgs, List constructorArgTypes) + { + var project = (Project) PluginBase.CurrentProject; + if (ProcessWizard(dialog, inDirectory, name, project, out var path, out var newFilePath)) return; + lastFileFromTemplate = newFilePath; + WizardContext.constructorArgs = constructorArgs; + WizardContext.constructorArgTypes = constructorArgTypes; + lastFileOptions = GetWizardOptions(project, dialog, typeTemplate); + FileFromTemplate(path, templateFile, newFilePath); + } + + public static bool ProcessWizard(IWizard dialog, string inDirectory, string name, Project project, out string path, out string newFilePath) + { + var classpath = project.AbsoluteClasspaths.GetClosestParent(inDirectory); + if (classpath is null) + { + if (project.AdditionalPaths is { } paths) classpath = PathCollection.GetClosestParent(inDirectory, paths); + classpath ??= inDirectory; + } + + var package = GetPackage(project, ref classpath, inDirectory); + dialog.Project = project; + dialog.Directory = inDirectory; + dialog.StartupClassName = name; + package = package.Replace(Path.DirectorySeparatorChar, '.'); + dialog.StartupPackage = package; + + var conflictResult = DialogResult.OK; + var ext = project.DefaultSearchFilter.Split(';').FirstOrDefault() ?? string.Empty; + if (ext.Length > 0) ext = ext.TrimStart('*'); + do + { + if (dialog.ShowDialog() != DialogResult.OK) + { + path = null; + newFilePath = null; + return true; + } + var cPackage = dialog.GetPackage(); + path = Path.Combine(classpath, cPackage.Replace('.', Path.DirectorySeparatorChar)); + newFilePath = Path.ChangeExtension(Path.Combine(path, dialog.GetName()), ext); + if (!File.Exists(newFilePath)) continue; + var title = " " + TextHelper.GetString("FlashDevelop.Title.ConfirmDialog"); + var message = TextHelper.GetString("PluginCore.Info.FolderAlreadyContainsFile"); + conflictResult = MessageBox.Show(PluginBase.MainForm, + string.Format(message, newFilePath, "\n"), title, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); + if (conflictResult == DialogResult.No) return true; + } while (conflictResult == DialogResult.Cancel); + return false; + } + + static AS3ClassOptions GetWizardOptions(IProject project, IWizard dialog, string typeTemplate) + { + return new AS3ClassOptions( + language: project.Language, + package: dialog.GetPackage(), + super_class: dialog.GetExtends(), + Interfaces: dialog.GetInterfaces(), + is_public: dialog.IsPublic(), + is_dynamic: dialog.IsDynamic(), + is_final: dialog.IsFinal(), + create_inherited: dialog.GetGenerateInheritedMethods(), + create_constructor: dialog.GetGenerateConstructor() + ) {Template = typeTemplate}; + } + + static void FileFromTemplate(string directoryPath, string templateFile, string filePath) + { + try + { + if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); + PluginBase.MainForm.FileFromTemplate(templateFile + ".wizard", filePath); + } + catch (Exception ex) + { + ErrorManager.ShowError(ex); + } + } + + static string GetPackage(Project project, ref string classpath, string inDirectory) + { + try + { + var package = GetPackage(classpath, inDirectory); + if (string.IsNullOrEmpty(package) && !project.AdditionalPaths.IsNullOrEmpty()) + { + var closest = ""; + foreach (var it in project.AdditionalPaths) + if ((classpath.StartsWithOrdinal(it) || it == ".") && it.Length > closest.Length) + closest = it; + if (closest.Length > 0) package = GetPackage(closest, inDirectory); + } + if (package != "") return package; + // search in Global classpath + var info = new Hashtable {["language"] = project.Language}; + var de = new DataEvent(EventType.Command, "ASCompletion.GetUserClasspath", info); + EventManager.DispatchEvent(null, de); + if (de.Handled && info.ContainsKey("cp") && info["cp"] is List cps) + { + foreach (var cp in cps) + { + package = GetPackage(cp, inDirectory); + if (package.Length == 0) continue; + classpath = cp; + break; + } + } + return package; + } + catch (NullReferenceException) + { + return string.Empty; + } + } + + static string GetPackage(string classpath, string path) + { + if (!path.StartsWith(classpath, StringComparison.OrdinalIgnoreCase)) return string.Empty; + return path.Substring(classpath.Length) + .Trim('/', '\\', ' ', '.') + .Replace(Path.DirectorySeparatorChar, '.'); + } + + public static string ProcessArgs(string args) + { + if (lastFileFromTemplate is null) return args; + var package = lastFileOptions != null ? lastFileOptions.Package : ""; + var fileName = Path.GetFileNameWithoutExtension(lastFileFromTemplate); + args = args.Replace("$(FileName)", fileName); + if (args.Contains("$(FileNameWithPackage)") || args.Contains("$(Package)")) + { + args = args.Replace("$(Package)", package); + args = package.Length != 0 + ? args.Replace("$(FileNameWithPackage)", package + "." + fileName) + : args.Replace("$(FileNameWithPackage)", fileName); + if (lastFileOptions != null) + { + args = ProcessFileTemplate(args); + if (processOnSwitch is null) lastFileOptions = null; + } + } + lastFileFromTemplate = null; + return args; + } + + static string ProcessFileTemplate(string args) + { + var eolMode = (int)PluginBase.Settings.EOLMode; + var lineBreak = LineEndDetector.GetNewLineMarker(eolMode); + var imports = new List(); + var extends = ""; + var implements = ""; + var paramString = ""; + var superConstructor = ""; + int index; + // resolve imports + if (!lastFileOptions.interfaces.IsNullOrEmpty()) + { + string implementContinuation; + implements = " implements "; + index = 0; + + if (lastFileOptions.Language == "haxe") + { + var isHaxe2 = PluginBase.CurrentSDK != null && PluginBase.CurrentSDK.Name.ToLower().Contains("haxe 2"); + implementContinuation = isHaxe2 ? ", implements " : " implements "; + } + else + { + implementContinuation = ", "; + } + + foreach (var item in lastFileOptions.interfaces) + { + if (item.Contains('.')) imports.Add(item); + implements += (index > 0 ? implementContinuation : "") + item.Split('.').Last(); + if (lastFileOptions.createInheritedMethods) + { + processOnSwitch = lastFileFromTemplate; + // let ASCompletion generate the implementations when file is opened + } + index++; + } + } + if (!string.IsNullOrEmpty(lastFileOptions.superClass)) + { + var superClassFullName = lastFileOptions.superClass; + if (superClassFullName.Contains('.')) imports.Add(superClassFullName); + var superClassShortName = superClassFullName.Split('.').Last(); + var fileName = Path.GetFileNameWithoutExtension(lastFileFromTemplate); + extends = fileName == superClassShortName ? $" extends {superClassFullName}" : $" extends {superClassShortName}"; + if (lastFileOptions.createConstructor + && constructorArgs is null + && ASContext.GetLanguageContext(lastFileOptions.Language) is { } ctx) + { + var lastDotIndex = superClassFullName.LastIndexOf('.'); + var cmodel = ctx.GetModel(lastDotIndex == -1 ? "" : superClassFullName.Substring(0, lastDotIndex), superClassShortName, ""); + if (!cmodel.IsVoid()) + { + if ((cmodel.Flags & FlagType.TypeDef) != 0) + cmodel.SearchMember(FlagType.Constructor, true, out cmodel); + foreach (var member in cmodel.Members) + { + if (member.Name != cmodel.Constructor) continue; + paramString = member.ParametersString(); + AddImports(ctx, member, cmodel.InFile, imports); + superConstructor = "super("; + index = 0; + if (member.Parameters != null) + foreach (var param in member.Parameters) + { + if (param.Name.StartsWith('.')) break; + var pname = TemplateUtils.GetParamName(param); + superConstructor += (index > 0 ? ", " : "") + pname; + index++; + } + superConstructor += ");\n" + (lastFileOptions.Language == "as3" ? "\t\t\t" : "\t\t"); + break; + } + } + } + } + if (constructorArgs != null) + { + paramString = constructorArgs; + foreach (var type in constructorArgTypes) + { + if (!imports.Contains(type)) + { + imports.Add(type); + } + } + } + string access; + var classMetadata = ""; + if (lastFileOptions.Language == "as3") + { + access = lastFileOptions.isPublic ? "public " : "internal "; + access += lastFileOptions.isDynamic ? "dynamic " : ""; + access += lastFileOptions.isFinal ? "final " : ""; + } + else if (lastFileOptions.Language == "haxe") + { + access = lastFileOptions.isPublic ? "public " : "private "; + access += lastFileOptions.isDynamic ? "dynamic " : ""; + if (lastFileOptions.isFinal) classMetadata += "@:final\n"; + } + else access = lastFileOptions.isDynamic ? "dynamic " : ""; + var importsSrc = ""; + string prevImport = null; + imports.Sort(); + foreach (var import in imports) + { + if (prevImport == import) continue; + prevImport = import; + if (import.LastIndexOf('.') is { } p && (p == -1 || import.Substring(0, p) == lastFileOptions.Package)) continue; + importsSrc += (lastFileOptions.Language == "as3" ? "\t" : "") + "import " + import + ";" + lineBreak; + } + if (importsSrc.Length > 0) importsSrc += (lastFileOptions.Language == "as3" ? "\t" : "") + lineBreak; + args = args.Replace("$(Template)", lastFileOptions.Template ?? string.Empty); + args = args.Replace("$(Import)", importsSrc); + args = args.Replace("$(Extends)", extends); + args = args.Replace("$(Implements)", implements); + args = args.Replace("$(Access)", access); + args = args.Replace("$(InheritedMethods)", string.Empty); + args = args.Replace("$(ConstructorArguments)", paramString); + args = args.Replace("$(Super)", superConstructor); + args = args.Replace("$(ClassMetadata)", classMetadata); + return args; + } + + static void AddImports(IASContext ctx, MemberModel member, FileModel inFile, ICollection result) + { + var types = new List {member.Type}; + if (member.Parameters != null) types.AddRange(member.Parameters.Select(static it => it.Type)); + foreach (var type in ASContext.Context.DecomposeTypes(types)) + { + AddImport(ctx, type, inFile, result); + } + } + + static void AddImport(IASContext ctx, string cname, FileModel inFile, ICollection result) + { + var aClass = ctx.ResolveType(cname, inFile); + if (!aClass.IsVoid() && aClass.InFile.Package != "") + { + result.Add(aClass.QualifiedName); + } + } + } +} \ No newline at end of file diff --git a/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.cs b/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.cs index 6dff19f955..fd85b04245 100644 --- a/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.cs +++ b/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.cs @@ -9,15 +9,14 @@ using ProjectManager.Projects; using ASCompletion.Context; using ASCompletion.Model; -using System.Reflection; using System.Diagnostics; +using System.Linq; using PluginCore.Controls; namespace ASClassWizard.Wizards { - public partial class AS3ClassWizard : SmartForm, IThemeHandler + public partial class AS3ClassWizard : SmartForm, IThemeHandler, IWizard { - private string directoryPath; private Project project; public const string REG_IDENTIFIER_AS = "^[a-zA-Z_$][a-zA-Z0-9_$]*$"; // $ is not a valid char in haxe class names @@ -30,7 +29,7 @@ public AS3ClassWizard() CenterToParent(); this.FormGuid = "eb444130-58ea-47bd-9751-ad78a59c711f"; this.Font = PluginBase.Settings.DefaultFont; - this.errorIcon.Image = PluginMain.MainForm.FindImage("197"); + this.errorIcon.Image = PluginBase.MainForm.FindImage("197"); } public void AfterTheming() @@ -60,25 +59,21 @@ private void LocalizeText() this.cancelButton.Text = TextHelper.GetString("Wizard.Button.Cancel"); } - public String StartupPackage + public string StartupPackage { - set { packageBox.Text = value; } + set => packageBox.Text = value; } - public String StartupClassName + public string StartupClassName { - set { classBox.Text = value; } - } - - public string Directory - { - get { return this.directoryPath; } - set { this.directoryPath = value; } + set => classBox.Text = value; } + public string Directory { get; set; } + public Project Project { - get { return project; } + get => project; set { this.project = value; @@ -88,35 +83,38 @@ public Project Project this.publicRadio.Enabled = false; this.internalRadio.Enabled = false; this.finalCheck.Enabled = false; - this.titleLabel.Text = TextHelper.GetString("Wizard.Label.NewAs2Class"); - this.Text = TextHelper.GetString("Wizard.Label.NewAs2Class"); + var label = TextHelper.GetString("Wizard.Label.NewAs2Class"); + this.titleLabel.Text = label; + this.Text = label; } if (project.Language == "haxe") { this.internalRadio.Text = "private"; - this.titleLabel.Text = TextHelper.GetString("Wizard.Label.NewHaxeClass"); - this.Text = TextHelper.GetString("Wizard.Label.NewHaxeClass"); + var label = TextHelper.GetString("Wizard.Label.NewHaxeClass"); + this.titleLabel.Text = label; + this.Text = label; } else { - this.titleLabel.Text = TextHelper.GetString("Wizard.Label.NewAs3Class"); - this.Text = TextHelper.GetString("Wizard.Label.NewAs3Class"); + var label = TextHelper.GetString("Wizard.Label.NewAs3Class"); + this.titleLabel.Text = label; + this.Text = label; } } } private void ValidateClass() { - string errorMessage = ""; - string regex = (project.Language == "haxe") ? REG_IDENTIFIER_HAXE : REG_IDENTIFIER_AS; - if (getClassName() == "") + var errorMessage = ""; + var regex = (project.Language == "haxe") ? REG_IDENTIFIER_HAXE : REG_IDENTIFIER_AS; + if (GetName().Length == 0) errorMessage = TextHelper.GetString("Wizard.Error.EmptyClassName"); - else if (!Regex.Match(getClassName(), regex, RegexOptions.Singleline).Success) + else if (!Regex.Match(GetName(), regex, RegexOptions.Singleline).Success) errorMessage = TextHelper.GetString("Wizard.Error.InvalidClassName"); - else if (project.Language == "haxe" && Char.IsLower(getClassName()[0])) + else if (project.Language == "haxe" && char.IsLower(GetName()[0])) errorMessage = TextHelper.GetString("Wizard.Error.LowercaseClassName"); - if (errorMessage != "") + if (errorMessage.Length != 0) { okButton.Enabled = false; errorIcon.Visible = true; @@ -136,33 +134,30 @@ private void ValidateClass() /// private void packageBrowse_Click(object sender, EventArgs e) { + using PackageBrowser browser = new PackageBrowser(); + browser.Project = this.Project; - using (PackageBrowser browser = new PackageBrowser()) - { - browser.Project = this.Project; + foreach (string item in Project.AbsoluteClasspaths) + browser.AddClassPath(item); - foreach (string item in Project.AbsoluteClasspaths) - browser.AddClassPath(item); - - if (browser.ShowDialog(this) == DialogResult.OK) + if (browser.ShowDialog(this) == DialogResult.OK) + { + if (browser.Package != null) { - if (browser.Package != null) + string classpath = this.Project.AbsoluteClasspaths.GetClosestParent(browser.Package); + string package = Path.GetDirectoryName(ProjectPaths.GetRelativePath(classpath, Path.Combine(browser.Package, "foo"))); + if (package != null) { - string classpath = this.Project.AbsoluteClasspaths.GetClosestParent(browser.Package); - string package = Path.GetDirectoryName(ProjectPaths.GetRelativePath(classpath, Path.Combine(browser.Package, "foo"))); - if (package != null) - { - directoryPath = browser.Package; - package = package.Replace(Path.DirectorySeparatorChar, '.'); - this.packageBox.Text = package; - } - } - else - { - this.directoryPath = browser.Project.Directory; - this.packageBox.Text = ""; + Directory = browser.Package; + package = package.Replace(Path.DirectorySeparatorChar, '.'); + this.packageBox.Text = package; } } + else + { + this.Directory = browser.Project.Directory; + this.packageBox.Text = ""; + } } } @@ -174,22 +169,20 @@ private void AS3ClassWizard_Load(object sender, EventArgs e) private void baseBrowse_Click(object sender, EventArgs e) { - using (ClassBrowser browser = new ClassBrowser()) + using ClassBrowser browser = new ClassBrowser(); + IASContext context = ASContext.GetLanguageContext(PluginBase.CurrentProject.Language); + try { - IASContext context = ASContext.GetLanguageContext(PluginBase.CurrentProject.Language); - try - { - browser.ClassList = context.GetAllProjectClasses(); - } - catch { } - browser.ExcludeFlag = FlagType.Interface; - browser.IncludeFlag = FlagType.Class; - if (browser.ShowDialog(this) == DialogResult.OK) - { - this.baseBox.Text = browser.SelectedClass; - } - this.okButton.Focus(); + browser.ClassList = context.GetAllProjectClasses(); + } + catch { } + browser.ExcludeFlag = FlagType.Interface; + browser.IncludeFlag = FlagType.Class; + if (browser.ShowDialog(this) == DialogResult.OK) + { + this.baseBox.Text = browser.SelectedClass; } + this.okButton.Focus(); } /// @@ -197,37 +190,35 @@ private void baseBrowse_Click(object sender, EventArgs e) /// private void implementBrowse_Click(object sender, EventArgs e) { - using (ClassBrowser browser = new ClassBrowser()) + using var browser = new ClassBrowser(); + MemberList known = null; + browser.IncludeFlag = FlagType.Interface; + var context = ASContext.GetLanguageContext(PluginBase.CurrentProject.Language); + try { - MemberList known = null; - browser.IncludeFlag = FlagType.Interface; - IASContext context = ASContext.GetLanguageContext(PluginBase.CurrentProject.Language); - try - { - known = context.GetAllProjectClasses(); - known.Merge(ASContext.Context.GetVisibleExternalElements()); - } - catch (Exception error) - { - Debug.WriteLine(error.StackTrace); - } - browser.ClassList = known; - if (browser.ShowDialog(this) == DialogResult.OK) + known = context.GetAllProjectClasses(); + known.Merge(ASContext.Context.GetVisibleExternalElements()); + } + catch (Exception error) + { + Debug.WriteLine(error.StackTrace); + } + browser.ClassList = known; + if (browser.ShowDialog(this) == DialogResult.OK) + { + if (browser.SelectedClass != null) { - if (browser.SelectedClass != null) + foreach (string item in this.implementList.Items) { - foreach (string item in this.implementList.Items) - { - if (item == browser.SelectedClass) return; - } - this.implementList.Items.Add(browser.SelectedClass); + if (item == browser.SelectedClass) return; } + this.implementList.Items.Add(browser.SelectedClass); } - this.implementRemove.Enabled = this.implementList.Items.Count > 0; - this.implementList.SelectedIndex = this.implementList.Items.Count - 1; - this.superCheck.Enabled = this.implementList.Items.Count > 0; - ValidateClass(); } + this.implementRemove.Enabled = this.implementList.Items.Count > 0; + this.implementList.SelectedIndex = this.implementList.Items.Count - 1; + this.superCheck.Enabled = this.implementList.Items.Count > 0; + ValidateClass(); } /// @@ -266,70 +257,30 @@ private void baseBox_TextChanged(object sender, EventArgs e) #endregion - public static Image GetResource(string resourceID) - { - resourceID = "ASClassWizard." + resourceID; - Assembly assembly = Assembly.GetExecutingAssembly(); - Image image = new Bitmap(assembly.GetManifestResourceStream(resourceID)); - return image; - } - #region user_options - public string getPackage() - { - return this.packageBox.Text; - } + public string GetPackage() => packageBox.Text; - public string getClassName() - { - return this.classBox.Text; - } + public string GetName() => classBox.Text; - public bool isDynamic() - { - return this.dynamicCheck.Checked; - } + public bool IsDynamic() => dynamicCheck.Checked; - public bool isFinal() - { - return this.finalCheck.Checked; - } + public bool IsFinal() => finalCheck.Checked; - public bool isPublic() - { - return this.publicRadio.Checked; - } + public bool IsPublic() => publicRadio.Checked; - public string getSuperClass() - { - return this.baseBox.Text; - } + public string GetExtends() => baseBox.Text; - public List getInterfaces() + public List GetInterfaces() { - List _interfaces = new List(this.implementList.Items.Count); - foreach (string item in this.implementList.Items) - { - _interfaces.Add(item); - } - return _interfaces; + return implementList.Items.Cast().ToList(); } - public bool hasInterfaces() - { - return this.implementList.Items.Count > 0; - } + public bool HasInterfaces() => implementList.Items.Count > 0; - public bool getGenerateConstructor() - { - return this.constructorCheck.Checked; - } + public bool GetGenerateConstructor() => constructorCheck.Checked; - public bool getGenerateInheritedMethods() - { - return this.superCheck.Checked; - } + public bool GetGenerateInheritedMethods() => superCheck.Checked; #endregion diff --git a/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.designer.cs b/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.designer.cs index b9359cf86e..5426397627 100644 --- a/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.designer.cs +++ b/External/Plugins/ASClassWizard/Wizards/AS3ClassWizard.designer.cs @@ -1,7 +1,4 @@ - -using ASClassWizard.Resources; - -namespace ASClassWizard.Wizards +namespace ASClassWizard.Wizards { partial class AS3ClassWizard { @@ -432,7 +429,8 @@ private void InitializeComponent() // // flowLayoutPanel1 // - this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.flowLayoutPanel1.AutoSize = true; this.flowLayoutPanel1.Controls.Add(this.cancelButton); diff --git a/External/Plugins/ASClassWizard/Wizards/AS3InterfaceWizard.cs b/External/Plugins/ASClassWizard/Wizards/AS3InterfaceWizard.cs new file mode 100644 index 0000000000..e02caf3d2a --- /dev/null +++ b/External/Plugins/ASClassWizard/Wizards/AS3InterfaceWizard.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using ASCompletion.Context; +using ASCompletion.Model; +using PluginCore; +using PluginCore.Controls; +using PluginCore.Localization; +using ProjectManager.Projects; + +namespace ASClassWizard.Wizards +{ + public partial class AS3InterfaceWizard : SmartForm, IThemeHandler, IWizard + { + Project project; + public const string REG_IDENTIFIER_AS = "^[a-zA-Z_$][a-zA-Z0-9_$]*$"; + // $ is not a valid char in haxe class names + public const string REG_IDENTIFIER_HAXE = "^[a-zA-Z_][a-zA-Z0-9_]*$"; + + public AS3InterfaceWizard() + { + InitializeComponent(); + LocalizeText(); + CenterToParent(); + FormGuid = "E1D36E71-BD39-4C58-A436-F46D01EC0590"; + Font = PluginBase.Settings.DefaultFont; + errorIcon.Image = PluginBase.MainForm.FindImage("197"); + } + + public void AfterTheming() + { + var color = PluginBase.MainForm.GetThemeColor("ListBox.BackColor", SystemColors.Window); + var color1 = PluginBase.MainForm.GetThemeColor("Control.BackColor", SystemColors.Control); + flowLayoutPanel1.BackColor = color1; + flowLayoutPanel9.BackColor = color; + titleLabel.BackColor = color; + } + + void LocalizeText() + { + typeLabel.Text = TextHelper.GetString("Wizard.Label.Name"); + baseLabel.Text = TextHelper.GetString("Wizard.Label.ExtendsInterface"); + packageLabel.Text = TextHelper.GetString("Wizard.Label.Package"); + packageBrowse.Text = TextHelper.GetString("Wizard.Button.Browse"); + baseBrowse.Text = TextHelper.GetString("Wizard.Button.Browse"); + okButton.Text = TextHelper.GetString("Wizard.Button.Ok"); + cancelButton.Text = TextHelper.GetString("Wizard.Button.Cancel"); + } + + public string StartupPackage + { + set => packageBox.Text = value; + } + + public string StartupClassName + { + set => classBox.Text = value; + } + + public string Directory { get; set; } + + public Project Project + { + get => project; + set + { + project = value; + if (project.Language == "as2") + { + var label = TextHelper.GetString("Wizard.Label.NewAs2Interface"); + titleLabel.Text = label; + Text = label; + } + else if (project.Language == "haxe") + { + var label = TextHelper.GetString("Wizard.Label.NewHaxeInterface"); + titleLabel.Text = label; + Text = label; + } + else + { + var label = TextHelper.GetString("Wizard.Label.NewAs3Interface"); + titleLabel.Text = label; + Text = label; + } + } + } + + void ValidateClass() + { + var errorMessage = ""; + var regex = (project.Language == "haxe") ? REG_IDENTIFIER_HAXE : REG_IDENTIFIER_AS; + if (GetName().Length == 0) + errorMessage = TextHelper.GetString("Wizard.Error.EmptyInterfaceName"); + else if (!Regex.Match(GetName(), regex, RegexOptions.Singleline).Success) + errorMessage = TextHelper.GetString("Wizard.Error.InvalidInterfaceName"); + else if (project.Language == "haxe" && char.IsLower(GetName()[0])) + errorMessage = TextHelper.GetString("Wizard.Error.LowercaseInterfaceName"); + + if (errorMessage.Length != 0) + { + okButton.Enabled = false; + errorIcon.Visible = true; + } + else + { + okButton.Enabled = true; + errorIcon.Visible = false; + } + errorLabel.Text = errorMessage; + } + + #region EventHandlers + + /// + /// Browse project packages + /// + void packageBrowse_Click(object sender, EventArgs e) + { + using PackageBrowser browser = new PackageBrowser(); + browser.Project = Project; + + foreach (string item in Project.AbsoluteClasspaths) + browser.AddClassPath(item); + + if (browser.ShowDialog(this) == DialogResult.OK) + { + if (browser.Package != null) + { + string classpath = Project.AbsoluteClasspaths.GetClosestParent(browser.Package); + string package = Path.GetDirectoryName(ProjectPaths.GetRelativePath(classpath, Path.Combine(browser.Package, "foo"))); + if (package != null) + { + Directory = browser.Package; + package = package.Replace(Path.DirectorySeparatorChar, '.'); + packageBox.Text = package; + } + } + else + { + Directory = browser.Project.Directory; + packageBox.Text = ""; + } + } + } + + void AS3ClassWizard_Load(object sender, EventArgs e) + { + classBox.Select(); + ValidateClass(); + } + + void baseBrowse_Click(object sender, EventArgs e) + { + using var browser = new ClassBrowser(); + var context = ASContext.GetLanguageContext(PluginBase.CurrentProject.Language); + try + { + browser.ClassList = context.GetAllProjectClasses(); + } + catch { } + browser.IncludeFlag = FlagType.Interface; + if (browser.ShowDialog(this) == DialogResult.OK) + { + baseBox.Text = browser.SelectedClass; + } + okButton.Focus(); + } + + void packageBox_TextChanged(object sender, EventArgs e) + { + ValidateClass(); + } + + void classBox_TextChanged(object sender, EventArgs e) + { + ValidateClass(); + } + + void baseBox_TextChanged(object sender, EventArgs e) + { + ValidateClass(); + } + + #endregion + + #region user_options + + public string GetPackage() => packageBox.Text; + + public string GetName() => classBox.Text; + + public string GetExtends() => baseBox.Text; + + #endregion + + public List GetInterfaces() => null; + + public bool IsPublic() => true; + + public bool IsDynamic() => false; + + public bool IsFinal() => false; + + public bool GetGenerateInheritedMethods() => false; + + public bool GetGenerateConstructor() => false; + } +} diff --git a/External/Plugins/ASClassWizard/Wizards/AS3InterfaceWizard.designer.cs b/External/Plugins/ASClassWizard/Wizards/AS3InterfaceWizard.designer.cs new file mode 100644 index 0000000000..f448287d61 --- /dev/null +++ b/External/Plugins/ASClassWizard/Wizards/AS3InterfaceWizard.designer.cs @@ -0,0 +1,345 @@ + +namespace ASClassWizard.Wizards +{ + partial class AS3InterfaceWizard + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.baseBox = new System.Windows.Forms.TextBoxEx(); + this.classBox = new System.Windows.Forms.TextBoxEx(); + this.packageBox = new System.Windows.Forms.TextBoxEx(); + this.typeLabel = new System.Windows.Forms.Label(); + this.baseLabel = new System.Windows.Forms.Label(); + this.packageLabel = new System.Windows.Forms.Label(); + this.packageBrowse = new System.Windows.Forms.ButtonEx(); + this.baseBrowse = new System.Windows.Forms.ButtonEx(); + this.errorLabel = new System.Windows.Forms.Label(); + this.errorIcon = new System.Windows.Forms.PictureBox(); + this.flowLayoutPanel6 = new System.Windows.Forms.FlowLayoutPanel(); + this.flowLayoutPanel9 = new System.Windows.Forms.FlowLayoutPanel(); + this.titleLabel = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBoxEx(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.cancelButton = new System.Windows.Forms.ButtonEx(); + this.okButton = new System.Windows.Forms.ButtonEx(); + ((System.ComponentModel.ISupportInitialize)(this.errorIcon)).BeginInit(); + this.flowLayoutPanel6.SuspendLayout(); + this.flowLayoutPanel9.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.flowLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // baseBox + // + this.baseBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.baseBox.BorderColor = System.Drawing.SystemColors.ControlDark; + this.baseBox.Enabled = false; + this.baseBox.Location = new System.Drawing.Point(106, 63); + this.baseBox.Name = "baseBox"; + this.baseBox.Size = new System.Drawing.Size(267, 20); + this.baseBox.TabIndex = 9; + this.baseBox.UseTheme = true; + this.baseBox.TextChanged += new System.EventHandler(this.baseBox_TextChanged); + // + // classBox + // + this.classBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.classBox.BorderColor = System.Drawing.SystemColors.ControlDark; + this.classBox.Location = new System.Drawing.Point(106, 34); + this.classBox.Name = "classBox"; + this.classBox.Size = new System.Drawing.Size(267, 20); + this.classBox.TabIndex = 7; + this.classBox.Text = "INewInterface"; + this.classBox.UseTheme = true; + this.classBox.TextChanged += new System.EventHandler(this.classBox_TextChanged); + // + // packageBox + // + this.packageBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.packageBox.BorderColor = System.Drawing.SystemColors.ControlDark; + this.packageBox.Location = new System.Drawing.Point(106, 5); + this.packageBox.Name = "packageBox"; + this.packageBox.Size = new System.Drawing.Size(267, 20); + this.packageBox.TabIndex = 1; + this.packageBox.UseTheme = true; + this.packageBox.TextChanged += new System.EventHandler(this.packageBox_TextChanged); + // + // typeLabel + // + this.typeLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.typeLabel.AutoSize = true; + this.typeLabel.Location = new System.Drawing.Point(3, 37); + this.typeLabel.Name = "typeLabel"; + this.typeLabel.Size = new System.Drawing.Size(49, 13); + this.typeLabel.TabIndex = 6; + this.typeLabel.Text = "Interface"; + // + // baseLabel + // + this.baseLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.baseLabel.AutoSize = true; + this.baseLabel.Location = new System.Drawing.Point(3, 66); + this.baseLabel.Name = "baseLabel"; + this.baseLabel.Size = new System.Drawing.Size(75, 13); + this.baseLabel.TabIndex = 8; + this.baseLabel.Text = "Base interface"; + // + // packageLabel + // + this.packageLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.packageLabel.AutoSize = true; + this.packageLabel.Location = new System.Drawing.Point(3, 8); + this.packageLabel.Name = "packageLabel"; + this.packageLabel.Size = new System.Drawing.Size(50, 13); + this.packageLabel.TabIndex = 0; + this.packageLabel.Text = "Package"; + // + // packageBrowse + // + this.packageBrowse.Anchor = System.Windows.Forms.AnchorStyles.None; + this.packageBrowse.DisabledBackColor = System.Drawing.SystemColors.Control; + this.packageBrowse.DisabledTextColor = System.Drawing.SystemColors.ControlDark; + this.packageBrowse.Location = new System.Drawing.Point(381, 3); + this.packageBrowse.Name = "packageBrowse"; + this.packageBrowse.Size = new System.Drawing.Size(74, 23); + this.packageBrowse.TabIndex = 2; + this.packageBrowse.Text = "Browse..."; + this.packageBrowse.UseTheme = true; + this.packageBrowse.UseVisualStyleBackColor = true; + this.packageBrowse.Click += new System.EventHandler(this.packageBrowse_Click); + // + // baseBrowse + // + this.baseBrowse.Anchor = System.Windows.Forms.AnchorStyles.None; + this.baseBrowse.DisabledBackColor = System.Drawing.SystemColors.Control; + this.baseBrowse.DisabledTextColor = System.Drawing.SystemColors.ControlDark; + this.baseBrowse.Location = new System.Drawing.Point(381, 61); + this.baseBrowse.Name = "baseBrowse"; + this.baseBrowse.Size = new System.Drawing.Size(74, 23); + this.baseBrowse.TabIndex = 10; + this.baseBrowse.Text = "Browse..."; + this.baseBrowse.UseTheme = true; + this.baseBrowse.UseVisualStyleBackColor = true; + this.baseBrowse.Click += new System.EventHandler(this.baseBrowse_Click); + // + // errorLabel + // + this.errorLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.errorLabel.AutoSize = true; + this.errorLabel.ForeColor = System.Drawing.Color.Black; + this.errorLabel.Location = new System.Drawing.Point(25, 4); + this.errorLabel.Name = "errorLabel"; + this.errorLabel.Size = new System.Drawing.Size(29, 13); + this.errorLabel.TabIndex = 0; + this.errorLabel.Text = "Error"; + // + // errorIcon + // + this.errorIcon.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.errorIcon.Location = new System.Drawing.Point(3, 3); + this.errorIcon.Name = "errorIcon"; + this.errorIcon.Size = new System.Drawing.Size(16, 16); + this.errorIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.errorIcon.TabIndex = 0; + this.errorIcon.TabStop = false; + // + // flowLayoutPanel6 + // + this.flowLayoutPanel6.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel6.Controls.Add(this.errorIcon); + this.flowLayoutPanel6.Controls.Add(this.errorLabel); + this.flowLayoutPanel6.Location = new System.Drawing.Point(5, 3); + this.flowLayoutPanel6.Name = "flowLayoutPanel6"; + this.flowLayoutPanel6.Size = new System.Drawing.Size(296, 23); + this.flowLayoutPanel6.TabIndex = 0; + // + // flowLayoutPanel9 + // + this.flowLayoutPanel9.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel9.BackColor = System.Drawing.SystemColors.Window; + this.flowLayoutPanel9.Controls.Add(this.titleLabel); + this.flowLayoutPanel9.Location = new System.Drawing.Point(12, 12); + this.flowLayoutPanel9.Name = "flowLayoutPanel9"; + this.flowLayoutPanel9.Padding = new System.Windows.Forms.Padding(5); + this.flowLayoutPanel9.Size = new System.Drawing.Size(466, 35); + this.flowLayoutPanel9.TabIndex = 0; + // + // titleLabel + // + this.titleLabel.Anchor = System.Windows.Forms.AnchorStyles.None; + this.titleLabel.AutoSize = true; + this.titleLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.titleLabel.Location = new System.Drawing.Point(8, 5); + this.titleLabel.Name = "titleLabel"; + this.titleLabel.Size = new System.Drawing.Size(169, 13); + this.titleLabel.TabIndex = 0; + this.titleLabel.Text = "New Actionscript 2 Interface"; + // + // groupBox2 + // + this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox2.BorderColor = System.Drawing.SystemColors.ControlDark; + this.groupBox2.Controls.Add(this.tableLayoutPanel2); + this.groupBox2.Location = new System.Drawing.Point(10, 53); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(468, 104); + this.groupBox2.TabIndex = 1; + this.groupBox2.TabStop = false; + this.groupBox2.UseTheme = true; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanel2.ColumnCount = 3; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.42382F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 72.57618F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 83F)); + this.tableLayoutPanel2.Controls.Add(this.baseBrowse, 2, 2); + this.tableLayoutPanel2.Controls.Add(this.packageBrowse, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.packageLabel, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.packageBox, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.baseBox, 1, 2); + this.tableLayoutPanel2.Controls.Add(this.baseLabel, 0, 2); + this.tableLayoutPanel2.Controls.Add(this.typeLabel, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.classBox, 1, 1); + this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 12); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 3; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(460, 88); + this.tableLayoutPanel2.TabIndex = 0; + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel1.AutoSize = true; + this.flowLayoutPanel1.Controls.Add(this.cancelButton); + this.flowLayoutPanel1.Controls.Add(this.okButton); + this.flowLayoutPanel1.Controls.Add(this.flowLayoutPanel6); + this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft; + this.flowLayoutPanel1.Location = new System.Drawing.Point(12, 163); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(466, 29); + this.flowLayoutPanel1.TabIndex = 2; + // + // cancelButton + // + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.DisabledBackColor = System.Drawing.SystemColors.Control; + this.cancelButton.DisabledTextColor = System.Drawing.SystemColors.ControlDark; + this.cancelButton.Location = new System.Drawing.Point(388, 3); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 2; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseTheme = true; + this.cancelButton.UseVisualStyleBackColor = true; + // + // okButton + // + this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.okButton.DisabledBackColor = System.Drawing.SystemColors.Control; + this.okButton.DisabledTextColor = System.Drawing.SystemColors.ControlDark; + this.okButton.Enabled = false; + this.okButton.Location = new System.Drawing.Point(307, 3); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 1; + this.okButton.Text = "Ok"; + this.okButton.UseTheme = true; + this.okButton.UseVisualStyleBackColor = true; + // + // AS3InterfaceWizard + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(490, 204); + this.Controls.Add(this.flowLayoutPanel1); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.flowLayoutPanel9); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AS3InterfaceWizard"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "New ActionScript Interface"; + this.Load += new System.EventHandler(this.AS3ClassWizard_Load); + ((System.ComponentModel.ISupportInitialize)(this.errorIcon)).EndInit(); + this.flowLayoutPanel6.ResumeLayout(false); + this.flowLayoutPanel6.PerformLayout(); + this.flowLayoutPanel9.ResumeLayout(false); + this.flowLayoutPanel9.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.flowLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label packageLabel; + private System.Windows.Forms.Label typeLabel; + private System.Windows.Forms.Label baseLabel; + private System.Windows.Forms.Label errorLabel; + private System.Windows.Forms.PictureBox errorIcon; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel6; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel9; + private System.Windows.Forms.Label titleLabel; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.TextBoxEx packageBox; + private System.Windows.Forms.ButtonEx packageBrowse; + private System.Windows.Forms.TextBoxEx classBox; + private System.Windows.Forms.TextBoxEx baseBox; + private System.Windows.Forms.ButtonEx baseBrowse; + private System.Windows.Forms.GroupBoxEx groupBox2; + private System.Windows.Forms.ButtonEx cancelButton; + private System.Windows.Forms.ButtonEx okButton; + } +} + diff --git a/External/Plugins/ASClassWizard/Wizards/ClassBrowser.cs b/External/Plugins/ASClassWizard/Wizards/ClassBrowser.cs index 1e0ca9b697..863abb3233 100644 --- a/External/Plugins/ASClassWizard/Wizards/ClassBrowser.cs +++ b/External/Plugins/ASClassWizard/Wizards/ClassBrowser.cs @@ -10,44 +10,21 @@ namespace ASClassWizard.Wizards { public partial class ClassBrowser : SmartForm { - private MemberList all; - private List dataProvider; - private FlagType invalidFlag; - private FlagType validFlag; private int resultCount; private int topIndex; private int lastScore; private string matchToken; private int matchLen; - public MemberList ClassList - { - get { return this.all; } - set { this.all = value; } - } + public MemberList ClassList { get; set; } - public List DataProvider - { - get { return this.dataProvider; } - set { this.dataProvider = value; } - } + public List DataProvider { get; set; } - public FlagType ExcludeFlag - { - get { return this.invalidFlag; } - set { this.invalidFlag = value; } - } + public FlagType ExcludeFlag { get; set; } - public FlagType IncludeFlag - { - get { return this.validFlag; } - set { this.validFlag = value; } - } + public FlagType IncludeFlag { get; set; } - public string SelectedClass - { - get { return this.itemList.SelectedItem != null ? this.itemList.SelectedItem.ToString() : null; } - } + public string SelectedClass => itemList.SelectedItem?.ToString(); public ClassBrowser() { @@ -70,7 +47,6 @@ private void InitializeLocalization() private void ClassBrowser_Load(object sender, EventArgs e) { - ListBox.ListBoxItem node; this.itemList.BeginUpdate(); this.itemList.Items.Clear(); if (this.ClassList != null) @@ -85,7 +61,7 @@ private void ClassBrowser_Load(object sender, EventArgs e) if (!((item.Flags & IncludeFlag) > 0)) continue; } if (this.itemList.Items.Count > 0 && item.Name == this.itemList.Items[this.itemList.Items.Count - 1].ToString()) continue; - node = new ListBox.ListBoxItem(item.Name, (item.Flags & FlagType.Interface) > 0 ? 6 : 8); + var node = new ListBox.ListBoxItem(item.Name, (item.Flags & FlagType.Interface) > 0 ? 6 : 8); this.itemList.Items.Add(node); this.DataProvider.Add(node); } @@ -102,7 +78,7 @@ private void ClassBrowser_Load(object sender, EventArgs e) /// /// Filter the list /// - private void filterBox_TextChanged(Object sender, EventArgs e) + private void filterBox_TextChanged(object sender, EventArgs e) { this.itemList.BeginUpdate(); this.itemList.Items.Clear(); @@ -147,7 +123,8 @@ private bool FindAllItems(ListBox.ListBoxItem item) resultCount++; return true; } - else return false; + + return false; } /// diff --git a/External/Plugins/ASClassWizard/Wizards/IWizard.cs b/External/Plugins/ASClassWizard/Wizards/IWizard.cs new file mode 100644 index 0000000000..c5087e6f4d --- /dev/null +++ b/External/Plugins/ASClassWizard/Wizards/IWizard.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Windows.Forms; +using ProjectManager.Projects; + +namespace ASClassWizard.Wizards +{ + public interface IWizard + { + Project Project { set; } + string Directory { set; } + string StartupClassName { set; } + string StartupPackage { set; } + string GetPackage(); + string GetName(); + string GetExtends(); + List GetInterfaces(); + bool IsPublic(); + bool IsDynamic(); + bool IsFinal(); + bool GetGenerateInheritedMethods(); + bool GetGenerateConstructor(); + DialogResult ShowDialog(); + } +} \ No newline at end of file diff --git a/External/Plugins/ASClassWizard/Wizards/ListBox.cs b/External/Plugins/ASClassWizard/Wizards/ListBox.cs index 1a09c52797..a70c496d03 100644 --- a/External/Plugins/ASClassWizard/Wizards/ListBox.cs +++ b/External/Plugins/ASClassWizard/Wizards/ListBox.cs @@ -6,8 +6,6 @@ namespace ASClassWizard.Wizards { public class ListBox : ListBoxEx, IThemeHandler { - private ImageList _myImageList; - public ListBox() { // Set owner draw mode @@ -15,11 +13,7 @@ public ListBox() this.DrawMode = DrawMode.OwnerDrawFixed; } - public ImageList ImageList - { - get { return _myImageList; } - set { _myImageList = value; } - } + public ImageList ImageList { get; set; } public void AfterTheming() { @@ -34,12 +28,11 @@ protected override void OnDrawItem( System.Windows.Forms.DrawItemEventArgs e ) { e.DrawBackground(); e.DrawFocusRectangle(); - ListBoxItem item; Rectangle bounds = e.Bounds; - Size imageSize = _myImageList.ImageSize; + Size imageSize = ImageList.ImageSize; try { - item = (ListBoxItem)Items[e.Index]; + var item = (ListBoxItem)Items[e.Index]; if (item.ImageIndex != -1) { ImageList.Draw(e.Graphics, bounds.Left, bounds.Top, item.ImageIndex); @@ -70,34 +63,22 @@ protected override void OnDrawItem( System.Windows.Forms.DrawItemEventArgs e ) public class ListBoxItem { - public int matchScore; - - private string _myText; - private int _myImageIndex; - // properties - public string Text - { - get { return _myText; } - set { _myText = value; } - } - public int ImageIndex - { - get { return _myImageIndex; } - set { _myImageIndex = value; } - } - - public ListBoxItem(string text, int index) - { - _myText = text; - _myImageIndex = index; - } - public ListBoxItem(string text) : this(text, -1) { } + public string Text { get; set; } + + public int ImageIndex { get; set; } + public ListBoxItem() : this("") { } - public override string ToString() + + public ListBoxItem(string text) : this(text, -1) { } + + public ListBoxItem(string text, int index) { - return _myText; + Text = text; + ImageIndex = index; } + + public override string ToString() => Text; } } } diff --git a/External/Plugins/ASClassWizard/Wizards/PackageBrowser.cs b/External/Plugins/ASClassWizard/Wizards/PackageBrowser.cs index 8883d8f59a..04923e8693 100644 --- a/External/Plugins/ASClassWizard/Wizards/PackageBrowser.cs +++ b/External/Plugins/ASClassWizard/Wizards/PackageBrowser.cs @@ -14,7 +14,6 @@ namespace ASClassWizard.Wizards public partial class PackageBrowser : SmartForm { List classpathList; - Project project; public PackageBrowser() { @@ -22,50 +21,32 @@ public PackageBrowser() InitializeComponent(); LocalizeTexts(); CenterToParent(); - this.FormGuid = "b5a7f1b4-959b-485b-a7d7-9b683191c0cf"; - this.Font = PluginBase.Settings.DefaultFont; - this.browserView.ImageList = Icons.ImageList; - this.browserView.BeforeExpand += onBeforeExpandNode; + FormGuid = "b5a7f1b4-959b-485b-a7d7-9b683191c0cf"; + Font = PluginBase.Settings.DefaultFont; + browserView.ImageList = Icons.ImageList; + browserView.BeforeExpand += OnBeforeExpandNode; } - private void LocalizeTexts() + void LocalizeTexts() { - this.inviteLabel.Text = TextHelper.GetString("Wizard.Label.ChosePackage"); - this.okButton.Text = TextHelper.GetString("Wizard.Button.Ok"); - this.cancelButton.Text = TextHelper.GetString("Wizard.Button.Cancel"); - this.Text = TextHelper.GetString("Wizard.Label.PackageSelection"); + inviteLabel.Text = TextHelper.GetString("Wizard.Label.ChosePackage"); + okButton.Text = TextHelper.GetString("Wizard.Button.Ok"); + cancelButton.Text = TextHelper.GetString("Wizard.Button.Cancel"); + Text = TextHelper.GetString("Wizard.Label.PackageSelection"); } - public Project Project - { - get { return project; } - set { this.project = value; } - } + public Project Project { get; set; } - public String Package - { - get { - return this.browserView.SelectedNode != null ? - ((SimpleDirectoryNode)this.browserView.SelectedNode).directoryPath : null; - } - } + public string Package => ((SimpleDirectoryNode) browserView.SelectedNode)?.directoryPath; - private void Initialize() - { - classpathList = new List(); - } + void Initialize() => classpathList = new List(); - public void AddClassPath(string value) - { - classpathList.Add(value); - } + public void AddClassPath(string value) => classpathList.Add(value); - private void RefreshTree() + void RefreshTree() { - SimpleDirectoryNode node; - - this.browserView.BeginUpdate(); - this.browserView.Nodes.Clear(); + browserView.BeginUpdate(); + browserView.Nodes.Clear(); if (classpathList.Count > 0) { @@ -78,45 +59,37 @@ private void RefreshTree() { if (!IsDirectoryExcluded(item)) { - node = new SimpleDirectoryNode(item, Path.Combine(cp, item)); - node.ImageIndex = Icons.Folder.Index; - node.SelectedImageIndex = Icons.Folder.Index; - this.browserView.Nodes.Add(node); + var node = new SimpleDirectoryNode(item, Path.Combine(cp, item)) + { + ImageIndex = Icons.Folder.Index, + SelectedImageIndex = Icons.Folder.Index + }; + browserView.Nodes.Add(node); } } } catch { } } } - this.browserView.EndUpdate(); + browserView.EndUpdate(); } - private void PackageBrowser_Load(object sender, EventArgs e) - { - RefreshTree(); - } + void PackageBrowser_Load(object sender, EventArgs e) => RefreshTree(); - private void onBeforeExpandNode(Object sender, TreeViewCancelEventArgs e) + void OnBeforeExpandNode(object sender, TreeViewCancelEventArgs e) { - SimpleDirectoryNode newNode; - - if (e.Node is SimpleDirectoryNode) + if (e.Node is SimpleDirectoryNode {dirty: true} node) { - SimpleDirectoryNode node = e.Node as SimpleDirectoryNode; - if (node.dirty) + node.dirty = false; + node.Nodes.Clear(); + foreach (string item in Directory.GetDirectories(node.directoryPath)) { - node.dirty = false; - e.Node.Nodes.Clear(); - - foreach (string item in Directory.GetDirectories(node.directoryPath)) + if (!IsDirectoryExcluded(item)) { - if (!IsDirectoryExcluded(item)) - { - newNode = new SimpleDirectoryNode(item, Path.Combine(node.directoryPath, item)); - newNode.ImageIndex = Icons.Folder.Index; - newNode.SelectedImageIndex = Icons.Folder.Index; - node.Nodes.Add(newNode); - } + var newNode = new SimpleDirectoryNode(item, Path.Combine(node.directoryPath, item)); + newNode.ImageIndex = Icons.Folder.Index; + newNode.SelectedImageIndex = Icons.Folder.Index; + node.Nodes.Add(newNode); } } } @@ -138,17 +111,17 @@ protected bool IsDirectoryExcluded(string path) return Project.IsPathHidden(path) && !Project.ShowHiddenPaths; } - private void okButton_Click(object sender, EventArgs e) + void okButton_Click(object sender, EventArgs e) { - this.DialogResult = DialogResult.OK; - this.Close(); + DialogResult = DialogResult.OK; + Close(); } - private void cancelButton_Click(object sender, EventArgs e) + void cancelButton_Click(object sender, EventArgs e) { - this.browserView.SelectedNode = null; - this.DialogResult = DialogResult.Cancel; - this.Close(); + browserView.SelectedNode = null; + DialogResult = DialogResult.Cancel; + Close(); } } } diff --git a/External/Plugins/ASClassWizard/Wizards/PackageBrowser.designer.cs b/External/Plugins/ASClassWizard/Wizards/PackageBrowser.designer.cs index 7745800c90..974a36fab2 100644 --- a/External/Plugins/ASClassWizard/Wizards/PackageBrowser.designer.cs +++ b/External/Plugins/ASClassWizard/Wizards/PackageBrowser.designer.cs @@ -1,6 +1,4 @@ -using ASClassWizard.Resources; - -namespace ASClassWizard.Wizards +namespace ASClassWizard.Wizards { partial class PackageBrowser { diff --git a/External/Plugins/ASCompletion/ASCompletion.csproj b/External/Plugins/ASCompletion/ASCompletion.csproj index 9ce5937f0b..ab09845c23 100644 --- a/External/Plugins/ASCompletion/ASCompletion.csproj +++ b/External/Plugins/ASCompletion/ASCompletion.csproj @@ -1,199 +1,126 @@  - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {4EBF2653-9654-4E40-880E-0046B3D6210E} - Library - Properties - ASCompletion - ASCompletion - - - - - 3.5 - - - v4.0 - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - DEBUG;TRACE - prompt - 4 - - - none - true - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - DEBUG;TRACE - prompt - 4 - false - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - - - x86 - ..\..\..\FlashDevelop\Bin\Debug\Plugins\ - TRACE - true - - - - - - - - - - - - - - - - - - - - - Form - - - - - UserControl - - - ModelsExplorer.cs - - - - - - - - - - - - - - - UserControl - - - - - - Component - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {61885F70-B4DC-4B44-852D-5D6D03F2A734} - PluginCore - False - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - - - - - - - - - - - - - - - - - + + + + Debug + AnyCPU + {4EBF2653-9654-4E40-880E-0046B3D6210E} + Library + Properties + ASCompletion + ASCompletion + net48 + true + false + false + false + false + x64;x86;AnyCPU + + + true + full + false + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + prompt + 4 + 9 + + + false + none + true + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + 9 + + + true + full + false + x86 + DEBUG;TRACE + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + 4 + 9 + prompt + + + false + none + true + x86 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + 9 + + + true + full + false + x64 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + DEBUG;TRACE + 4 + 9 + prompt + + + false + none + true + x64 + ..\..\..\FlashDevelop\Bin\Debug\Plugins\ + TRACE + 9 + + + + + + + + + + {61885F70-B4DC-4B44-852D-5D6D03F2A734} + PluginCore + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/External/Plugins/ASCompletion/Commands/CallFlashIDE.cs b/External/Plugins/ASCompletion/Commands/CallFlashIDE.cs index 53f0c74336..ebfad8fc94 100644 --- a/External/Plugins/ASCompletion/Commands/CallFlashIDE.cs +++ b/External/Plugins/ASCompletion/Commands/CallFlashIDE.cs @@ -32,13 +32,13 @@ public class CallFlashIDE @"C:\Program Files\Macromedia\Flash MX 2004\Flash.exe", @"C:\Program Files (x86)\Macromedia\Flash MX 2004\Flash.exe" }; - static private DateTime lastRun; + private static DateTime lastRun; /// /// Return the path to the most recent Flash.exe /// /// - static public string FindFlashIDE() + public static string FindFlashIDE() { return FindFlashIDE(false); } @@ -48,7 +48,7 @@ static public string FindFlashIDE() /// /// Only AS3-capable authoring /// - static public string FindFlashIDE(bool AS3CapableOnly) + public static string FindFlashIDE(bool AS3CapableOnly) { string found = null; foreach (string flashexe in FLASHIDE_PATH) @@ -68,22 +68,22 @@ static public string FindFlashIDE(bool AS3CapableOnly) /// /// /// Operation successful - static public bool Run(string pathToIDE, string cmdData) + public static bool Run(string pathToIDE, string cmdData) { if (BridgeManager.Active) pathToIDE = "Flash"; else { - if (pathToIDE != null && Directory.Exists(pathToIDE)) + if (Directory.Exists(pathToIDE)) { var exe = Path.Combine(pathToIDE, "Animate.exe"); if (!File.Exists(exe)) exe = Path.Combine(pathToIDE, "Flash.exe"); pathToIDE = exe; } - if (pathToIDE == null || !File.Exists(pathToIDE)) + if (!File.Exists(pathToIDE)) { - string msg = TextHelper.GetString("Info.ConfigureFlashPath"); - string title = TextHelper.GetString("Info.ConfigurationRequired"); - DialogResult result = MessageBox.Show(msg, title, MessageBoxButtons.OKCancel); + var msg = TextHelper.GetString("Info.ConfigureFlashPath"); + var title = TextHelper.GetString("Info.ConfigurationRequired"); + var result = MessageBox.Show(msg, title, MessageBoxButtons.OKCancel); if (result == DialogResult.OK) { PluginBase.MainForm.ShowSettingsDialog("ASCompletion", "Flash"); @@ -100,7 +100,7 @@ static public bool Run(string pathToIDE, string cmdData) if (cmdData != null) { args = PluginBase.MainForm.ProcessArgString(cmdData); - if (args.IndexOf('"') < 0) args = '"' + args + '"'; + if (!args.Contains('"')) args = '"' + args + '"'; } // execution diff --git a/External/Plugins/ASCompletion/Commands/CreateTrustFile.cs b/External/Plugins/ASCompletion/Commands/CreateTrustFile.cs index 29ae987e43..39a654aa33 100644 --- a/External/Plugins/ASCompletion/Commands/CreateTrustFile.cs +++ b/External/Plugins/ASCompletion/Commands/CreateTrustFile.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Text; -using PluginCore; using PluginCore.Helpers; using PluginCore.Managers; @@ -19,19 +18,19 @@ public class CreateTrustFile /// Operation successful public static bool Run(string name, string path) { - if (name == null || path == null) return false; + if (name is null || path is null) return false; try { path += " "; string separator = Path.DirectorySeparatorChar.ToString(); string appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - string fixedPath = String.Format(FULLPATH, appDataDir, separator); + string fixedPath = string.Format(FULLPATH, appDataDir, separator); if (!Directory.Exists(fixedPath)) Directory.CreateDirectory(fixedPath); string file = Path.Combine(fixedPath, name); if (File.Exists(file)) { string src = FileHelper.ReadFile(file, Encoding.Default); - if (src.IndexOfOrdinal(path) < 0) FileHelper.AddToFile(file, "\r\n" + path, Encoding.Default); + if (!src.Contains(path)) FileHelper.AddToFile(file, "\r\n" + path, Encoding.Default); } else FileHelper.WriteFile(file, path, Encoding.Default); return true; diff --git a/External/Plugins/ASCompletion/Completion/ASComplete.cs b/External/Plugins/ASCompletion/Completion/ASComplete.cs index 6cef8da75f..7cc0e1e44e 100644 --- a/External/Plugins/ASCompletion/Completion/ASComplete.cs +++ b/External/Plugins/ASCompletion/Completion/ASComplete.cs @@ -1,8 +1,4 @@ -/* - * Code completion - */ - -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Drawing; @@ -21,6 +17,7 @@ using PluginCore.Managers; using PluginCore.Utilities; using ScintillaNet; +using ScintillaNet.Lexers; namespace ASCompletion.Completion { @@ -33,28 +30,30 @@ public class ASComplete { #region regular_expressions_definitions - static private readonly RegexOptions ro_csr = ASFileParserRegexOptions.SinglelineComment | RegexOptions.RightToLeft; + + const RegexOptions ro_csr = ASFileParserRegexOptions.SinglelineComment | RegexOptions.RightToLeft; + // refine last expression - static private readonly Regex re_refineExpression = new Regex("[^\\[\\]{}(:,=+*/%!<>-]*$", ro_csr); + static readonly Regex re_refineExpression = new Regex("[^\\[\\]'\"{}(:,=+*/%!<>-]*$", ro_csr); // code cleaning - static private readonly Regex re_whiteSpace = new Regex("[\\s]+", ASFileParserRegexOptions.SinglelineComment); + static readonly Regex re_whiteSpace = new Regex("[\\s]+", ASFileParserRegexOptions.SinglelineComment); // balanced matching, see: http://blogs.msdn.com/bclteam/archive/2005/03/15/396452.aspx - static private readonly Regex re_balancedParenthesis = new Regex("\\([^()]*(((?\\()[^()]*)+((?\\))[^()]*)+)*(?(Open)(?!))\\)", + static readonly Regex re_balancedParenthesis = new Regex("\\([^()]*(((?\\()[^()]*)+((?\\))[^()]*)+)*(?(Open)(?!))\\)", ASFileParserRegexOptions.SinglelineComment); // expressions - static private readonly Regex re_sub = new Regex("^#(?[0-9]+)~$", ASFileParserRegexOptions.SinglelineComment); + static readonly Regex re_sub = new Regex("^#(?[0-9]+)~$", ASFileParserRegexOptions.SinglelineComment); #endregion #region fields - static public Keys HelpKeys = Keys.F1; + public static Keys HelpKeys = Keys.F1; //stores the currently used class namespace and name - static private String currentClassHash = null; + static string currentClassHash; //stores the last completed member for each class - static private IDictionary completionHistory = new Dictionary(); + protected static readonly IDictionary completionHistory = new Dictionary(); - static public ResolvedContext CurrentResolvedContext; - static public event ResolvedContextChangeHandler OnResolvedContextChanged; + public static ResolvedContext CurrentResolvedContext; + public static event ResolvedContextChangeHandler OnResolvedContextChanged; #endregion @@ -62,174 +61,138 @@ public class ASComplete /// /// Character written in editor /// - /// Character inserted - static public bool OnChar(ScintillaControl Sci, int Value, bool autoHide) + /// Scintilla Control + /// Character inserted + /// Auto-started completion (is false when pressing Ctrl+Space or Ctrl+Alt+Space) + /// Auto-completion has been handled + public static bool OnChar(ScintillaControl sci, int value, bool autoHide) { - IASContext ctx = ASContext.Context; - ContextFeatures features = ctx.Features; - if (ctx.Settings == null || !ctx.Settings.CompletionEnabled) - return false; + if (sci.IsSelectionRectangle) return false; + var ctx = ASContext.Context; try { - if (Sci.IsSelectionRectangle) - return false; // code auto - int eolMode = Sci.EOLMode; - if (((Value == '\n') && (eolMode != 1)) || ((Value == '\r') && (eolMode == 1))) + int eolMode = sci.EOLMode; + if (((value == '\n') && (eolMode != 1)) || ((value == '\r') && (eolMode == 1))) { - if (ASContext.HasContext && ASContext.Context.IsFileValid) HandleStructureCompletion(Sci); + if (ASContext.HasContext && ctx.IsFileValid) HandleStructureCompletion(sci); return false; } - - int position = Sci.CurrentPos; + var position = sci.CurrentPos; if (position < 2) return false; - - char prevValue = (char) Sci.CharAt(position - 2); - bool skipQuoteCheck = false; - - Sci.Colourise(0, -1); - int style = Sci.BaseStyleAt(position - 1); - + var prevValue = (char) sci.CharAt(position - 2); + var skipQuoteCheck = false; + sci.Colourise(0, -1); + var style = sci.BaseStyleAt(position - 1); + var features = ctx.Features; if (features.hasStringInterpolation && (IsStringStyle(style) || IsCharStyle(style))) { - char stringTypeChar = Sci.GetStringType(position - 2); // start from -2 in case the inserted char is ' or " - + var stringTypeChar = sci.GetStringType(position - 2); // start from -2 in case the inserted char is ' or " // string interpolation - if (features.stringInterpolationQuotes.IndexOf(stringTypeChar) >= 0 && - IsMatchingQuote(stringTypeChar, Sci.BaseStyleAt(position - 2))) + if (features.stringInterpolationQuotes.Contains(stringTypeChar) + && IsMatchingQuote(stringTypeChar, sci.BaseStyleAt(position - 2))) { - if (Value == '$' && !IsEscapedCharacter(Sci, position - 1, '$')) - { - return HandleInterpolationCompletion(Sci, autoHide, false); - } - else if (Value == '{' && prevValue == '$' && !IsEscapedCharacter(Sci, position - 2, '$')) + if (value == '$' && !ctx.CodeComplete.IsEscapedCharacter(sci, position - 1, '$')) + return HandleInterpolationCompletion(sci, autoHide, false); + if (value == '{' && prevValue == '$' && !ctx.CodeComplete.IsEscapedCharacter(sci, position - 2, '$')) { - if (autoHide) HandleAddClosingBraces(Sci, (char) Value, true); - return HandleInterpolationCompletion(Sci, autoHide, true); + if (autoHide) HandleAddClosingBraces(sci, (char) value, true); + return HandleInterpolationCompletion(sci, autoHide, true); } - else if (IsInterpolationExpr(Sci, position - 2)) - { + if (ctx.CodeComplete.IsStringInterpolationStyle(sci, position - 2)) skipQuoteCheck = true; // continue on with regular completion - } } } if (!skipQuoteCheck) { // ignore text in comments & quoted text - if (!IsTextStyle(style) && !IsTextStyle(Sci.BaseStyleAt(position))) + if (!IsTextStyle(style) && !IsTextStyle(sci.BaseStyleAt(position))) { // documentation completion if (ASContext.CommonSettings.SmartTipsEnabled && IsCommentStyle(style)) { - return ASDocumentation.OnChar(Sci, Value, position, style); + return ASDocumentation.OnChar(sci, value, position, style); } - else if (autoHide) + if (autoHide) { // close quotes - HandleAddClosingBraces(Sci, (char) Value, true); - return false; + HandleAddClosingBraces(sci, (char) value, true); } + return false; } } // close brace/parens - if (autoHide) HandleAddClosingBraces(Sci, (char) Value, true); + if (autoHide) HandleAddClosingBraces(sci, (char) value, true); // stop here if the class is not valid - if (!ASContext.HasContext || !ASContext.Context.IsFileValid) return false; + if (!ASContext.HasContext || !ctx.IsFileValid) return false; - // handle - switch (Value) + if (ctx.CodeComplete.IsAvailable(ctx, autoHide)) { - case '.': - if (features.dot == "." || !autoHide) - return HandleDotCompletion(Sci, autoHide); - break; + // Custom completion + if (ctx.CodeComplete.OnChar(sci, value, prevValue, autoHide)) return true; + switch (value) + { + case '.': + if (features.dot == "." || !autoHide) return HandleDotCompletion(sci, autoHide); + break; - case '>': - if (features.dot == "->" && prevValue == '-') - return HandleDotCompletion(Sci, autoHide); - break; + case '>': + if (features.dot == "->" && prevValue == '-') return HandleDotCompletion(sci, autoHide); + break; - case ' ': - position--; - string word = GetWordLeft(Sci, ref position); - if (word.Length == 0) - { - char c = (char)Sci.CharAt(position); - if (c == ':' && features.hasEcmaTyping) - return HandleColonCompletion(Sci, "", autoHide); - else if (autoHide && (c == '(' || c == ',') && !ASContext.CommonSettings.DisableCallTip) - return HandleFunctionCompletion(Sci, autoHide); + case ' ': + if (ctx.CodeComplete.HandleWhiteSpaceCompletion(sci, position, autoHide)) return true; break; - } - if (word == "package" || Array.IndexOf(features.typesKeywords, word) >= 0) - return false; - // new/extends/instanceof/... - if (features.HasTypePreKey(word)) return HandleNewCompletion(Sci, "", autoHide, word); - var beforeBody = true; - var expr = CurrentResolvedContext?.Result?.Context; - if (expr != null) beforeBody = expr.ContextFunction == null || expr.BeforeBody; - if (!beforeBody && features.codeKeywords.Contains(word)) return false; - // override - if (word == features.overrideKey) return ASGenerator.HandleGeneratorCompletion(Sci, autoHide, word); - // import - if (features.hasImports && (word == features.importKey || word == features.importKeyAlt)) - return HandleImportCompletion(Sci, "", autoHide); - // public/internal/private/protected/static - if (Array.IndexOf(features.accessKeywords, word) >= 0) - return HandleDeclarationCompletion(Sci, "", autoHide); - break; - case ':': - if (ASContext.Context.CurrentModel.haXe && prevValue == '@') - { - return HandleMetadataCompletion(autoHide); - } - if (features.hasEcmaTyping) - { - return HandleColonCompletion(Sci, "", autoHide); - } - else break; + case ':': + if (features.hasEcmaTyping) return HandleColonCompletion(sci, string.Empty, autoHide); + break; - case '<': - if (features.hasGenerics && position > 2) - { - char c0 = (char)Sci.CharAt(position - 2); - //TODO: We should check if we are actually on a generic type - if ((ASContext.Context.CurrentModel.Version == 3 && c0 == '.') || Char.IsLetterOrDigit(c0)) - return HandleColonCompletion(Sci, "", autoHide); - return false; - } - else break; + case '<': + if (features.hasGenerics && position > 2) + { + var c0 = (char) sci.CharAt(position - 2); + //TODO: We should check if we are actually on a generic type + if ((ctx.CurrentModel.Version == 3 && c0 == '.') || char.IsLetterOrDigit(c0)) + return HandleColonCompletion(sci, string.Empty, autoHide); + return false; + } + break; + default: + AutoStartCompletion(sci, position); + break; + } + } + switch (value) + { case '(': case ',': - if (!ASContext.CommonSettings.DisableCallTip) - return HandleFunctionCompletion(Sci, autoHide); - else return false; + return !ASContext.CommonSettings.DisableCallTip && HandleFunctionCompletion(sci, autoHide); case ')': if (UITools.CallTip.CallTipActive) UITools.CallTip.Hide(); return false; case '*': - if (features.hasImportsWildcard) return CodeAutoOnChar(Sci, Value); + if (features.hasImportsWildcard) return CodeAutoOnChar(sci, value); break; case ';': - if (!ASContext.CommonSettings.DisableCodeReformat) - ReformatLine(Sci, position); - break; - - default: - AutoStartCompletion(Sci, position); + if (!ASContext.CommonSettings.DisableCodeReformat) ReformatLine(sci, position); break; } } - catch (Exception ex) { + catch (Exception ex) + { + #if DEBUG + throw; + #else ErrorManager.ShowError(/*"Completion error",*/ ex); + #endif } // CodeAuto context @@ -237,92 +200,104 @@ static public bool OnChar(ScintillaControl Sci, int Value, bool autoHide) return false; } - internal static void OnTextChanged(ScintillaControl sci, int position, int length, int linesAdded) + /// + /// Character written in editor + /// + /// Scintilla Control + /// Character inserted + /// Character before inserted character + /// Auto-started completion (is false when pressing Ctrl+Space or Ctrl+Alt+Space) + /// Auto-completion has been handled + protected virtual bool OnChar(ScintillaControl sci, int value, char prevValue, bool autoHide) => false; + + /// + /// Returns true if completion is available + /// + /// + /// Auto-started completion (is false when pressing Ctrl+Space or Ctrl+Alt+Space) + /// true if completion is available + protected virtual bool IsAvailable(IASContext ctx, bool autoHide) => ctx.Settings != null && ctx.Settings.CompletionEnabled; + + /// + /// Returns true if position is available for tooltip + /// + /// Scintilla Control + /// Cursor position + /// true if position is available for tooltip + protected internal virtual bool IsAvailableForToolTip(ScintillaControl sci, int position) { - // TODO track text changes -> LastChar + var style = sci.StyleAt(position); + return IsTextStyle(style) || (ASContext.Context.Features.hasInterfaces && IsStringInterpolationStyle(sci, position)); } /// /// Handle shortcuts /// /// Test keys + /// Scintilla Control /// - static public bool OnShortcut(Keys keys, ScintillaControl Sci) + public static bool OnShortcut(Keys keys, ScintillaControl sci) { - if (Sci.IsSelectionRectangle) - return false; - + if (sci.IsSelectionRectangle) return false; // dot complete if (keys == (Keys.Control | Keys.Space)) { - if (ASContext.HasContext && ASContext.Context.IsFileValid) - { - // try to get completion as if we had just typed the previous char - if (OnChar(Sci, Sci.CharAt(Sci.PositionBefore(Sci.CurrentPos)), false)) - return true; - else - { - // force dot completion - OnChar(Sci, '.', false); - return true; - } - } - else return false; + if (!ASContext.HasContext || !ASContext.Context.IsFileValid) return false; + // try to get completion as if we had just typed the previous char + if (OnChar(sci, sci.CharAt(sci.PositionBefore(sci.CurrentPos)), false)) return true; + // force dot completion + OnChar(sci, '.', false); + return true; } - else if (keys == Keys.Back) + if (keys == Keys.Back) { - HandleAddClosingBraces(Sci, Sci.CurrentChar, false); + HandleAddClosingBraces(sci, sci.CurrentChar, false); return false; } // show calltip - else if (keys == (Keys.Control | Keys.Shift | Keys.Space)) + if (keys == (Keys.Control | Keys.Shift | Keys.Space)) { - if (ASContext.HasContext && ASContext.Context.IsFileValid) - { - //HandleFunctionCompletion(Sci); - // force function completion - OnChar(Sci, '(', false); - return true; - } - else return false; + if (!ASContext.HasContext || !ASContext.Context.IsFileValid) return false; + // force function completion + OnChar(sci, '(', false); + return true; } // project types completion - else if (keys == (Keys.Control | Keys.Alt | Keys.Space)) + if (keys == (Keys.Control | Keys.Alt | Keys.Space)) { - if (ASContext.HasContext && ASContext.Context.IsFileValid && !ASContext.Context.Settings.LazyClasspathExploration) + if (!ASContext.HasContext + || !ASContext.Context.IsFileValid + || ASContext.Context.Settings.LazyClasspathExploration) return false; + var word = GetWordLeft(sci, sci.CurrentPos - 1); + if (word.Length > 0) { - int position = Sci.CurrentPos-1; - string tail = GetWordLeft(Sci, ref position); - ContextFeatures features = ASContext.Context.Features; - if (tail.IndexOfOrdinal(features.dot) < 0 && features.HasTypePreKey(tail)) tail = ""; - // display the full project classes list - HandleAllClassesCompletion(Sci, tail, false, true); - return true; + var features = ASContext.Context.Features; + if (!word.Contains(features.dot) && features.HasTypePreKey(word)) word = string.Empty; } - else return false; + // display the full project classes list + HandleAllClassesCompletion(sci, word, false, true); + return true; } // hot build - else if (keys == (Keys.Control | Keys.Enter)) + if (keys == (Keys.Control | Keys.Enter)) { // project build - DataEvent de = new DataEvent(EventType.Command, "ProjectManager.HotBuild", null); + var de = new DataEvent(EventType.Command, "ProjectManager.HotBuild", null); EventManager.DispatchEvent(ASContext.Context, de); - // if (!de.Handled) { // quick build if (!ASContext.Context.BuildCMD(true)) { // Flash IDE - if (PluginBase.CurrentProject == null) + if (PluginBase.CurrentProject is null) { - string idePath = ASContext.CommonSettings.PathToFlashIDE; - if (idePath != null && File.Exists(Path.Combine(idePath, "Flash.exe"))) + var idePath = ASContext.CommonSettings.PathToFlashIDE; + if (File.Exists(Path.Combine(idePath, "Flash.exe"))) { - string cmd = Path.Combine("Tools", Path.Combine("flashide", "testmovie.jsfl")); + var cmd = Path.Combine("Tools", "flashide", "testmovie.jsfl"); cmd = PathHelper.ResolvePath(cmd); - if (cmd != null && File.Exists(cmd)) - CallFlashIDE.Run(idePath, cmd); + if (File.Exists(cmd)) CallFlashIDE.Run(idePath, cmd); } } } @@ -330,9 +305,9 @@ static public bool OnShortcut(Keys keys, ScintillaControl Sci) return true; } // help - else if (keys == HelpKeys && ASContext.HasContext && ASContext.Context.IsFileValid) + if (keys == HelpKeys && ASContext.HasContext && ASContext.Context.IsFileValid) { - ResolveElement(Sci, "ShowDocumentation"); + ResolveElement(sci, "ShowDocumentation"); return true; } return false; @@ -340,76 +315,64 @@ static public bool OnShortcut(Keys keys, ScintillaControl Sci) /// /// Fire the completion automatically + /// Scintilla Control + /// Cursor position /// - private static void AutoStartCompletion(ScintillaControl Sci, int position) - { - if (!CompletionList.Active && ASContext.Context.Features.hasEcmaTyping - && ASContext.CommonSettings.AlwaysCompleteWordLength > 0) - { - // fire completion if starting to write a word - bool valid = true; - int n = ASContext.CommonSettings.AlwaysCompleteWordLength; - int wordStart = Sci.WordStartPosition(position, true); - if (position - wordStart != n) - return; - char c = (char)Sci.CharAt(wordStart); - string characterClass = ScintillaControl.Configuration.GetLanguage(Sci.ConfigurationLanguage).characterclass.Characters; - if (Char.IsDigit(c) || characterClass.IndexOf(c) < 0) - return; - // give a guess to the context (do not complete where it should not) - if (valid) - { - int pos = wordStart - 1; - c = ' '; - char c2 = ' '; - bool hadWS = false; - bool canComplete = false; - while (pos > 0) + static void AutoStartCompletion(ScintillaControl sci, int position) + { + if (CompletionList.Active + || !ASContext.Context.Features.hasEcmaTyping + || ASContext.CommonSettings.AlwaysCompleteWordLength <= 0) return; + // fire completion if starting to write a word + var wordStart = sci.WordStartPosition(position, true); + if (position - wordStart < ASContext.CommonSettings.AlwaysCompleteWordLength) return; + var c = (char) sci.CharAt(wordStart); + if (char.IsDigit(c)) return; + var characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; + if (!characterClass.Contains(c)) return; + // give a guess to the context (do not complete where it should not) + var pos = wordStart - 1; + var hadWS = false; + var canComplete = false; + while (pos > 0) + { + c = (char) sci.CharAt(pos--); + if (hadWS && characterClass.Contains(c)) break; + if (c == '<' && ((char) sci.CharAt(pos + 2) == '/' || !hadWS)) break; + if (":;,+-*%!&|<>/{}()[=?".Contains(c)) + { + canComplete = true; + // TODO Add HTML lookup here + if (pos > 0 && c == '/' && (char) sci.CharAt(pos) == '<') canComplete = false; + break; + } + if (c <= ' ') + { + if (c == '\r' || c == '\n') { - c = (char)Sci.CharAt(pos--); - if (hadWS && characterClass.IndexOf(c) >= 0) break; - else if (c == '<' && ((char)Sci.CharAt(pos + 2) == '/' || !hadWS)) break; - else if (":;,+-*%!&|<>/{}()[=?".IndexOf(c) >= 0) - { - canComplete = true; - // TODO Add HTML lookup here - if (pos > 0) - { - char c0 = (char)Sci.CharAt(pos); - if (c == '/' && c0 == '<') canComplete = false; - } - break; - } - else if (c <= 32) - { - if (c == '\r' || c == '\n') - { - canComplete = true; - break; - } - else if (pos > 1) - { - int style = Sci.BaseStyleAt(pos - 1); - if (style == 19) - { - canComplete = true; - break; - } - } - hadWS = true; - } - else if (c != '.' && characterClass.IndexOf(c) < 0) - { - // TODO support custom DOT - canComplete = false; - break; - } - c2 = c; + canComplete = true; + break; + } + if (pos > 1 && sci.BaseStyleAt(pos - 1) == (int) CPP.GLOBALCLASS) + { + canComplete = true; + break; } - if (canComplete) HandleDotCompletion(Sci, true); + hadWS = true; + } + else if (c != '.' && !characterClass.Contains(c)) + { + // TODO support custom DOT + canComplete = false; + break; } } - } + canComplete |= hadWS + // for example: override ad + && sci.GetWordFromPosition(pos) is {Length: > 0} word + && ASContext.Context.Features.accessKeywords.Contains(word); + if (canComplete) HandleDotCompletion(sci, true); + } #endregion #region add_closing_braces @@ -417,12 +380,12 @@ private static void AutoStartCompletion(ScintillaControl Sci, int position) public static void HandleAddClosingBraces(ScintillaControl sci, char c, bool addedChar) { if (!ASContext.CommonSettings.AddClosingBraces) return; - + var ctx = ASContext.Context; if (addedChar) { - if (IsMatchingQuote(c, sci.BaseStyleAt(sci.CurrentPos - 2)) && IsEscapedCharacter(sci, sci.CurrentPos - 1)) - { - return; + if (IsMatchingQuote(c, sci.BaseStyleAt(sci.CurrentPos - 2)) && ctx.CodeComplete.IsEscapedCharacter(sci, sci.CurrentPos - 1)) + { + return; } bool undo = false; @@ -448,16 +411,17 @@ public static void HandleAddClosingBraces(ScintillaControl sci, char c, bool add } // not inside a string literal + int position = sci.CurrentPos - 1; if (!(IsStringStyle(styleBefore) && IsStringStyle(styleAfter)) && !(IsCharStyle(styleBefore) && IsCharStyle(styleAfter)) - || IsInterpolationExpr(sci, sci.CurrentPos - 1)) + || ctx.CodeComplete.IsStringInterpolationStyle(sci, position)) { char nextChar = sci.CurrentChar; int nextPos = sci.CurrentPos; - while (nextChar == ' ' || nextChar == '\t') // Don't skip new line characters - { - nextPos++; - nextChar = (char) sci.CharAt(nextPos); + while (nextChar == ' ' || nextChar == '\t') // Don't skip new line characters + { + nextPos++; + nextChar = (char) sci.CharAt(nextPos); } foreach (var brace in ASContext.CommonSettings.AddClosingBracesRules) @@ -476,10 +440,10 @@ public static void HandleAddClosingBraces(ScintillaControl sci, char c, bool add char nextChar = sci.CurrentChar; int nextPos = sci.CurrentPos; - while (nextChar == ' ' || nextChar == '\t') // Don't skip new line characters - { - nextPos++; - nextChar = (char) sci.CharAt(nextPos); + while (nextChar == ' ' || nextChar == '\t') // Don't skip new line characters + { + nextPos++; + nextChar = (char) sci.CharAt(nextPos); } foreach (var brace in ASContext.CommonSettings.AddClosingBracesRules) @@ -499,30 +463,23 @@ public static void HandleAddClosingBraces(ScintillaControl sci, char c, bool add { char open = (char) sci.CharAt(sci.CurrentPos - 1); - if (IsMatchingQuote(open, sci.BaseStyleAt(sci.CurrentPos - 2)) && IsEscapedCharacter(sci, sci.CurrentPos - 1)) - { - return; + if (IsMatchingQuote(open, sci.BaseStyleAt(sci.CurrentPos - 2)) && ctx.CodeComplete.IsEscapedCharacter(sci, sci.CurrentPos - 1)) + { + return; } int styleBefore = sci.BaseStyleAt(sci.CurrentPos - 2); int styleAfter = sci.BaseStyleAt(sci.CurrentPos); // not inside a string literal + int position = sci.CurrentPos - 1; if (!(IsStringStyle(styleBefore) && IsStringStyle(styleAfter)) && !(IsCharStyle(styleBefore) && IsCharStyle(styleAfter)) - || IsInterpolationExpr(sci, sci.CurrentPos - 1) + || ctx.CodeComplete.IsStringInterpolationStyle(sci, position) || IsMatchingQuote(open, styleAfter)) { - int closePos = sci.CurrentPos; - - while (char.IsWhiteSpace(c)) - { - closePos++; - c = (char) sci.CharAt(closePos); - } - foreach (var brace in ASContext.CommonSettings.AddClosingBracesRules) { - if (HandleBraceRemove(sci, brace, open, c, closePos)) + if (HandleBraceRemove(sci, brace, open)) { break; } @@ -531,56 +488,63 @@ public static void HandleAddClosingBraces(ScintillaControl sci, char c, bool add } } - private static bool HandleBraceOpen(ScintillaControl sci, Brace brace, char open, byte styleAfter, byte styleBefore) + static bool HandleBraceOpen(ScintillaControl sci, Brace brace, char open, byte styleAfter, byte styleBefore) { - if (open == brace.Open) + if (open != brace.Open) return false; + var charAfter = (char) sci.CharAt(sci.CurrentPos); + var charBefore = (char) sci.CharAt(sci.CurrentPos - 2); + if (!brace.ShouldOpen(charBefore, styleBefore, charAfter, styleAfter)) return false; + var selections = sci.GetSelections(); + var positions = new List(selections); + for (var i = selections - 1; i >= 0; i--) { - char charAfter = (char) sci.CharAt(sci.CurrentPos); - char charBefore = (char) sci.CharAt(sci.CurrentPos - 2); - - if (brace.ShouldOpen(charBefore, styleBefore, charAfter, styleAfter)) - { - sci.InsertText(-1, brace.Close.ToString()); - if (brace.AddSpace) - { - sci.AddText(1, " "); - } - return true; - } + positions.Add(sci.GetSelectionNStart(i)); } - - return false; - } - - private static bool HandleBraceClose(ScintillaControl sci, Brace brace, char close, char next, int nextPosition) - { - if (close == brace.Close && next == brace.Close) + positions.Sort(); + var braceString = brace.Close.ToString(); + for (var i = 0; i < selections; i++) { - if (brace.ShouldClose(sci.CurrentPos, nextPosition)) - { - sci.DeleteBack(); - sci.AnchorPosition = nextPosition; - sci.CurrentPos = nextPosition; - return true; - } + var position = positions[i] + i * braceString.Length; + sci.InsertText(position, braceString); + positions[i] = position; + if (!brace.AddSpace) continue; + sci.InsertText(position, " "); + if (i + 1 < selections) positions[i + 1] += " ".Length * (i + 1); } + sci.SetSelection(positions[0], positions[0]); + for (var i = 1; i < selections; i++) + { + var position = positions[i]; + sci.AddSelection(position, position); + } + return true; + } - return false; + static bool HandleBraceClose(ScintillaControl sci, Brace brace, char close, char next, int nextPosition) + { + if (close != brace.Close || next != brace.Close || !brace.ShouldClose(sci.CurrentPos, nextPosition)) + return false; + sci.DeleteBack(); + sci.AnchorPosition = nextPosition; + sci.CurrentPos = nextPosition; + return true; } - - private static bool HandleBraceRemove(ScintillaControl sci, Brace brace, char open, char close, int closePosition) + + static bool HandleBraceRemove(ScintillaControl sci, Brace brace, char open) { - if (open == brace.Open && close == brace.Close) - { - if (brace.ShouldRemove(sci.CurrentPos, closePosition)) - { - sci.SelectionEnd = closePosition + 1; - sci.DeleteBack(); - return true; - } + var result = false; + var selections = sci.GetSelections(); + for (var i = 0; i < selections; i++) + { + if (open != brace.Open) continue; + var startPosition = sci.GetSelectionNStart(i); + var closePosition = startPosition; + if (GetCharRight(sci, true, ref closePosition) != brace.Close || !brace.ShouldRemove(startPosition, closePosition)) continue; + sci.SetSelectionNStart(i, startPosition - 1); + sci.SetSelectionNEnd(i, closePosition + 1); + result = true; } - - return false; + return result; } #endregion @@ -589,57 +553,50 @@ private static bool HandleBraceRemove(ScintillaControl sci, Brace brace, char op /// /// Using the text under at cursor position, search and open the object/class/member declaration /// - /// Control + /// Scintilla Control /// Declaration was found public static bool DeclarationLookup(ScintillaControl sci) { - if (!ASContext.Context.IsFileValid || (sci == null)) return false; - + if (!ASContext.Context.IsFileValid || sci is null) return false; // let the context handle goto declaration if we couldn't find anything - if (!InternalDeclarationLookup(sci)) - { - ASExpr expression = GetExpression(sci, sci.CurrentPos); - if (expression != null) - { - return ASContext.Context.HandleGotoDeclaration(sci, expression); - } - } - return true; + if (InternalDeclarationLookup(sci)) return true; + var expression = GetExpression(sci, sci.CurrentPos); + return ASContext.Context.HandleGotoDeclaration(sci, expression); } public static bool TypeDeclarationLookup(ScintillaControl sci) { - if (sci == null || !ASContext.Context.IsFileValid) return false; + if (sci is null || !ASContext.Context.IsFileValid) return false; var position = ExpressionEndPosition(sci, sci.CurrentPos); var result = GetExpressionType(sci, position, false, true); if (result.IsPackage) return false; var member = result.Member; var type = result.Type; - if (member == null || member.Flags.HasFlag(FlagType.AutomaticVar) || type == null) return false; + if (member is null || member.Flags.HasFlag(FlagType.AutomaticVar) || type is null) return false; if (member.Flags.HasFlag(FlagType.Function)) { - type = ASContext.Context.ResolveType(result.Member.Type, result.InFile); + type = ResolveType(result.Member.Type, result.InFile); if (type.IsVoid()) return false; } result.Member = null; result.InClass = null; result.InFile = null; var path = type.Name; - result.Path = path.Contains(".") ? path.Substring(0, path.IndexOfOrdinal(".")) : path; + result.Path = path.Contains('.', out var index) + ? path.Substring(0, index) + : path; return OpenDocumentToDeclaration(sci, result); - } - - private static bool InternalDeclarationLookup(ScintillaControl sci) - { - // get type at cursor position + } + + static bool InternalDeclarationLookup(ScintillaControl sci) + { + // get type at cursor position var position = ExpressionEndPosition(sci, sci.CurrentPos); var result = GetExpressionType(sci, position, false, true); + var ctx = ASContext.Context; // browse to package folder - if (result.IsPackage && result.InFile != null) - { - return ASContext.Context.BrowseTo(result.InFile.Package); - } + if (result.IsPackage && result.InFile != null) return ctx.BrowseTo(result.InFile.Package); // open source and show declaration if (!result.IsNull()) @@ -651,90 +608,59 @@ private static bool InternalDeclarationLookup(ScintillaControl sci) return OpenDocumentToDeclaration(sci, result); } // show overridden method - else if (ASContext.Context.CurrentMember != null - && ASContext.Context.Features.overrideKey != null - && sci.GetWordFromPosition(position) == ASContext.Context.Features.overrideKey) - { - MemberModel member = ASContext.Context.CurrentMember; - if ((member.Flags & FlagType.Override) > 0) - { - ClassModel tmpClass = ASContext.Context.CurrentClass; - if (tmpClass != null) - { - tmpClass.ResolveExtends(); - tmpClass = tmpClass.Extends; - while (tmpClass != null && !tmpClass.IsVoid()) - { - MemberModel found = tmpClass.Members.Search(member.Name, 0, 0); - if (found != null) - { - result = new ASResult(); - result.Member = found; - result.InFile = tmpClass.InFile; - result.InClass = tmpClass; - OpenDocumentToDeclaration(sci, result); - break; - } - tmpClass = tmpClass.Extends; - } - } - } - } + if (ctx.CurrentMember is null + || ctx.Features.overrideKey is null + || sci.GetWordFromPosition(position) != ctx.Features.overrideKey) return false; + var member = ctx.CurrentMember; + if ((member.Flags & FlagType.Override) == 0) return false; + var found = ctx.CurrentClass.Extends.SearchMember(member.Name, true, out var inClass); + if (found != null) OpenDocumentToDeclaration(sci, new ASResult {Member = found, InFile = inClass.InFile, InClass = inClass}); return false; } - static public void SaveLastLookupPosition(ScintillaControl Sci) + public static void SaveLastLookupPosition(ScintillaControl sci) { - if (Sci != null) - { - int lookupLine = Sci.CurrentLine; - int lookupCol = Sci.CurrentPos - Sci.PositionFromLine(lookupLine); - ASContext.Panel.SetLastLookupPosition(ASContext.Context.CurrentFile, lookupLine, lookupCol); - } + if (sci is null) return; + var lookupLine = sci.CurrentLine; + var lookupCol = sci.CurrentPos - sci.PositionFromLine(lookupLine); + ASContext.Panel.SetLastLookupPosition(ASContext.Context.CurrentFile, lookupLine, lookupCol); } /// /// Show resolved element declaration /// - static public bool OpenDocumentToDeclaration(ScintillaControl Sci, ASResult result) + /// Scintilla control + /// Element declaration + public static bool OpenDocumentToDeclaration(ScintillaControl sci, ASResult result) { - FileModel model = result.InFile - ?? ((result.Member != null && result.Member.InFile != null) ? result.Member.InFile : null) - ?? ((result.Type != null) ? result.Type.InFile : null); - if (model == null || model.FileName == "") return false; - ClassModel inClass = result.InClass ?? result.Type; + var model = result.InFile ?? result.Member?.InFile ?? result.Type?.InFile; + if (string.IsNullOrEmpty(model?.FileName)) return false; + var inClass = result.InClass ?? result.Type; - SaveLastLookupPosition(Sci); + SaveLastLookupPosition(sci); if (model != ASContext.Context.CurrentModel) { - if (model.FileName.Length > 0 && File.Exists(model.FileName)) - ASContext.MainForm.OpenEditableDocument(model.FileName, false); + if (File.Exists(model.FileName)) PluginBase.MainForm.OpenEditableDocument(model.FileName, false); else { OpenVirtualFile(model); result.InFile = ASContext.Context.CurrentModel; - if (result.InFile == null) return false; + if (result.InFile is null) return false; if (inClass != null) { inClass = result.InFile.GetClassByName(inClass.Name); - if (result.Member != null) - result.Member = inClass.Members.Search(result.Member.Name, 0, 0); + if (result.Member != null) result.Member = inClass.Members.Search(result.Member.Name); } - else if (result.Member != null) - result.Member = result.InFile.Members.Search(result.Member.Name, 0, 0); + else if (result.Member != null) result.Member = result.InFile.Members.Search(result.Member.Name); } } - if ((inClass == null || inClass.IsVoid()) && result.Member == null) - return false; - - Sci = ASContext.CurSciControl; - if (Sci == null) - return false; + if ((inClass is null || inClass.IsVoid()) && result.Member is null) return false; + if (PluginBase.MainForm.CurrentDocument?.SciControl is null) return false; - int line = 0; + var line = 0; string name = null; - bool isClass = false; + var isClass = false; // member if (result.Member != null && result.Member.LineFrom > 0) { @@ -742,38 +668,37 @@ static public bool OpenDocumentToDeclaration(ScintillaControl Sci, ASResult resu name = result.Member.Name; } // class declaration - else if (inClass.LineFrom > 0) + else if (inClass != null && inClass.LineFrom > 0) { line = inClass.LineFrom; name = inClass.Name; isClass = true; // constructor - foreach (MemberModel member in inClass.Members) - if ((member.Flags & FlagType.Constructor) > 0) - { - line = member.LineFrom; - name = member.Name; - isClass = false; - break; - } + var member = inClass.SearchMember(FlagType.Constructor, false); + if (member != null) + { + line = member.LineFrom; + name = member.Name; + isClass = false; + } } // select if (line > 0) { - if (isClass) - LocateMember("(class|interface|abstract)", name, line); - else - LocateMember("(function|var|const|get|set|property|namespace|[,(])", name, line); + var keyword = isClass + ? "(class|interface|abstract)" + : "(function|var|const|get|set|property|namespace|[,(])"; + LocateMember(keyword, name, line); } return true; } - static public void OpenVirtualFile(FileModel model) + public static void OpenVirtualFile(FileModel model) { - string ext = Path.GetExtension(model.FileName); - if (ext == "") ext = model.Context.GetExplorerMask()[0].Replace("*", ""); - string dummyFile = Path.Combine(Path.GetDirectoryName(model.FileName), "[model] " + Path.GetFileNameWithoutExtension(model.FileName) + ext); - foreach (ITabbedDocument doc in ASContext.MainForm.Documents) + var ext = Path.GetExtension(model.FileName); + if (string.IsNullOrEmpty(ext)) ext = model.Context.GetExplorerMask()[0].Replace("*", string.Empty); + var dummyFile = Path.Combine(Path.GetDirectoryName(model.FileName), "[model] " + Path.GetFileNameWithoutExtension(model.FileName) + ext); + foreach (var doc in PluginBase.MainForm.Documents) { if (doc.FileName == dummyFile) { @@ -783,103 +708,104 @@ static public void OpenVirtualFile(FileModel model) } // nice output model.Members.Sort(); - foreach (ClassModel aClass in model.Classes) aClass.Members.Sort(); - string src = "//\n// " + model.FileName + "\n//\n" + model.GenerateIntrinsic(false); - ITabbedDocument temp = ASContext.MainForm.CreateEditableDocument(dummyFile, src, Encoding.UTF8.CodePage) as ITabbedDocument; - if (temp != null && temp.IsEditable) + foreach (var aClass in model.Classes) aClass.Members.Sort(); + var src = "//\n// " + model.FileName + "\n//\n" + model.GenerateIntrinsic(false); + if (PluginBase.MainForm.CreateEditableDocument(dummyFile, src, Encoding.UTF8.CodePage) is ITabbedDocument {SciControl: { } sci}) { // The model document will be read only - temp.SciControl.IsReadOnly = true; + sci.IsReadOnly = true; } } public static void LocateMember(string keyword, string name, int line) - { - LocateMember(PluginBase.MainForm.CurrentDocument.SciControl, keyword, name, line); - } + => LocateMember(PluginBase.MainForm.CurrentDocument?.SciControl, keyword, name, line); public static void LocateMember(ScintillaControl sci, string keyword, string name, int line) { - if (sci == null || line <= 0) return; - try - { - bool found = false; - string pattern = String.Format("{0}\\s*(?{1})[^A-z0-9]", (keyword ?? ""), name.Replace(".", "\\s*.\\s*")); - Regex re = new Regex(pattern); - for (int i = line; i < line + 2; i++) - if (i < sci.LineCount) - { - string text = sci.GetLine(i); - Match m = re.Match(text); - if (m.Success) - { - int position = sci.PositionFromLine(i) + sci.MBSafeTextLength(text.Substring(0, m.Groups["name"].Index)); - sci.EnsureVisibleEnforcePolicy(sci.LineFromPosition(position)); - sci.SetSel(position, position + m.Groups["name"].Length); - found = true; - break; - } - } + if (sci is null || line <= 0 || string.IsNullOrEmpty(name)) return; + ASContext.Context.CodeComplete.LocateMember(sci, line, keyword, name); + } - if (!found) - { - sci.EnsureVisible(line); - int linePos = sci.PositionFromLine(line); - sci.SetSel(linePos, linePos); - } - sci.Focus(); - } - catch { } + protected virtual void LocateMember(ScintillaControl sci, int line, string keyword, string name) + => LocateMember(sci, line, $"{keyword ?? string.Empty}\\s*(?{name.Replace(".", "\\s*.\\s*")})[^A-z0-9]"); + + protected void LocateMember(ScintillaControl sci, int line, string pattern) + { + var found = false; + var re = new Regex(pattern); + for (int i = line, lineCount = sci.LineCount; i < line + 2 && i < lineCount; i++) + { + var text = sci.GetLine(i); + var m = re.Match(text); + if (!m.Success) continue; + var position = sci.PositionFromLine(i) + sci.MBSafeTextLength(text.Substring(0, m.Groups["name"].Index)); + sci.EnsureVisibleEnforcePolicy(sci.LineFromPosition(position)); + sci.SetSel(position, position + m.Groups["name"].Length); + found = true; + break; + } + if (!found) + { + sci.EnsureVisible(line); + var linePos = sci.PositionFromLine(line); + sci.SetSel(linePos, linePos); + } + sci.Focus(); } /// /// Resolve word at cursor position and pre-fill arguments for args processor /// - internal static void ResolveContext(ScintillaControl Sci) + internal static void ResolveContext(ScintillaControl sci) { try { // check if a document - if (Sci == null) + if (sci is null) { ClearResolvedContext(); return; } - + var currentPos = sci.CurrentPos; // check if resolution is needed - int position = Sci.WordEndPosition(Sci.CurrentPos, true); + var position = sci.WordEndPosition(currentPos, true); if (CurrentResolvedContext != null && CurrentResolvedContext.Position == position && CurrentResolvedContext.Result != null && !CurrentResolvedContext.Result.IsNull()) return; // check context - IASContext context = ASContext.Context; - if (context == null || context.CurrentModel == null) + var context = ASContext.Context; + if (context?.CurrentModel is null) { ClearResolvedContext(); return; } - CurrentResolvedContext = new ResolvedContext(); - CurrentResolvedContext.Position = position; + CurrentResolvedContext = new ResolvedContext {Position = position}; + var features = context.Features; // get type at cursor position ASResult result; - if (ASContext.Context.IsFileValid) result = GetExpressionType(Sci, position); + if (context.IsFileValid + // comments + && sci.BaseStyleAt(currentPos) is { } style && !IsCommentStyle(style) + // keywords + && ((style != 19 && style != 24) || (!string.IsNullOrEmpty(features.ConstructorKey) && sci.GetWordFromPosition(currentPos) == features.ConstructorKey))) + { + result = GetExpressionType(sci, position); + } else result = new ASResult(); CurrentResolvedContext.Result = result; - ContextFeatures features = context.Features; - Hashtable args = CurrentResolvedContext.Arguments; - string package = context.CurrentModel.Package; + var args = CurrentResolvedContext.Arguments; + var package = context.CurrentModel.Package; args.Add("TypPkg", package); - ClassModel cClass = context.CurrentClass; - if (cClass == null) cClass = ClassModel.VoidClass; + var cClass = context.CurrentClass ?? ClassModel.VoidClass; args.Add("TypName", MemberModel.FormatType(cClass.Name)); - string fullname = MemberModel.FormatType(cClass.QualifiedName); - args.Add("TypPkgName", fullname); - FlagType flags = cClass.Flags; - string kind = GetKind(flags, features); + var fullName = MemberModel.FormatType(cClass.QualifiedName); + args.Add("TypPkgName", fullName); + var flags = cClass.Flags; + var kind = GetKind(flags, features); args.Add("TypKind", kind); if (context.CurrentMember != null) @@ -889,20 +815,19 @@ internal static void ResolveContext(ScintillaControl Sci) kind = GetKind(flags, features); args.Add("MbrKind", kind); - ClassModel aType = CurrentResolvedContext.TokenType - = ASContext.Context.ResolveType(context.CurrentMember.Type, context.CurrentModel); - package = aType.IsVoid() ? "" : aType.InFile.Package; + var aType = CurrentResolvedContext.TokenType = ResolveType(context.CurrentMember.Type, context.CurrentModel); + package = aType.IsVoid() ? string.Empty : aType.InFile.Package; args.Add("MbrTypPkg", package); args.Add("MbrTypName", MemberModel.FormatType(aType.Name)); - fullname = MemberModel.FormatType(aType.QualifiedName); - args.Add("MbrTypePkgName", fullname); + fullName = MemberModel.FormatType(aType.QualifiedName); + args.Add("MbrTypePkgName", fullName); flags = aType.Flags; kind = GetKind(flags, features); args.Add("MbrTypKind", kind); } else { - args.Add("MbrName", ""); + args.Add("MbrName", string.Empty); args.Add("MbrKind", ""); args.Add("MbrTypPkg", ""); args.Add("MbrTypName", ""); @@ -922,43 +847,41 @@ internal static void ResolveContext(ScintillaControl Sci) } else if (result.Type != null || result.Member != null) { - ClassModel oClass = result.InClass ?? result.Type; - - if (oClass.IsVoid() && (result.Member == null || (result.Member.Flags & FlagType.Function) == 0 && (result.Member.Flags & FlagType.Namespace) == 0)) - { + var oClass = result.InClass ?? result.Type ?? ClassModel.VoidClass; + if (oClass.IsVoid() && (result.Member is null || (result.Member.Flags & FlagType.Function) == 0 && (result.Member.Flags & FlagType.Namespace) == 0)) + { NotifyContextChanged(); - return; + return; } // type details FileModel file; - MemberModel member = result.Member; - + var member = result.Member; if (member != null && member.IsPackageLevel) { args.Add("ItmTypName", member.Name); file = member.InFile; - fullname = "package"; + fullName = "package"; flags = member.Flags; } else { args.Add("ItmTypName", MemberModel.FormatType(oClass.Name)); file = oClass.InFile; - fullname = MemberModel.FormatType(oClass.Name); + fullName = MemberModel.FormatType(oClass.Name); flags = oClass.Flags; } package = file.Package; - fullname = (package.Length > 0 ? package + "." : "") + fullname; + fullName = (package.Length > 0 ? package + "." : "") + fullName; kind = GetKind(flags, features); args.Add("ItmFile", file.FileName); args.Add("ItmTypPkg", package); - args.Add("ItmTypPkgName", fullname); + args.Add("ItmTypPkgName", fullName); args.Add("ItmTypKind", kind); // type as path - args.Add("ItmTypPkgNamePath", fullname.Replace('.', '\\')); - args.Add("ItmTypPkgNameURL", fullname.Replace('.', '/')); + args.Add("ItmTypPkgNamePath", fullName.Replace('.', '\\')); + args.Add("ItmTypPkgNameURL", fullName.Replace('.', '/')); if (result.Type != null) { @@ -1009,55 +932,51 @@ internal static void ResolveContext(ScintillaControl Sci) } NotifyContextChanged(); } - catch + catch { + // ignored } } - private static void ClearResolvedContext() + static void ClearResolvedContext() { - if (CurrentResolvedContext != null && CurrentResolvedContext.Position == -1) - return; + if (CurrentResolvedContext != null && CurrentResolvedContext.Position == -1) return; CurrentResolvedContext = new ResolvedContext(); NotifyContextChanged(); } - private static void NotifyContextChanged() - { - if (OnResolvedContextChanged != null) - OnResolvedContextChanged.Invoke(CurrentResolvedContext); - } + static void NotifyContextChanged() => OnResolvedContextChanged?.Invoke(CurrentResolvedContext); /// /// Using the text under at cursor position, resolve the member/type and call the specified command. /// - /// Control + /// Control + /// /// Resolved element details - static public Hashtable ResolveElement(ScintillaControl Sci, string eventAction) + public static Hashtable? ResolveElement(ScintillaControl sci, string eventAction) { - if (CurrentResolvedContext == null) ResolveContext(Sci); - + if (CurrentResolvedContext is null) ResolveContext(sci); if (eventAction != null && !CurrentResolvedContext.Result.IsNull()) { // other plugins may handle the request - DataEvent de = new DataEvent(EventType.Command, eventAction, CurrentResolvedContext.Arguments); + var de = new DataEvent(EventType.Command, eventAction, CurrentResolvedContext.Arguments); EventManager.DispatchEvent(ASContext.Context, de); if (de.Handled) return CurrentResolvedContext.Arguments; // help if (eventAction == "ShowDocumentation") { - string cmd = ASContext.Context.Settings.DocumentationCommandLine; + var cmd = ASContext.Context.Settings.DocumentationCommandLine; if (string.IsNullOrEmpty(cmd)) return null; // top-level vars should be searched only if the command includes member information - if (CurrentResolvedContext.Result.InClass == ClassModel.VoidClass && cmd.IndexOfOrdinal("$(Itm") < 0) + if (CurrentResolvedContext.Result.InClass == ClassModel.VoidClass && !cmd.Contains("$(Itm")) return null; // complete command cmd = ArgumentsProcessor.Process(cmd, CurrentResolvedContext.Arguments); // call the command try { - ASContext.MainForm.CallCommand("RunProcess", cmd); + PluginBase.MainForm.CallCommand("RunProcess", cmd); } catch (Exception ex) { @@ -1070,19 +989,14 @@ static public Hashtable ResolveElement(ScintillaControl Sci, string eventAction) public static void FindClosestList(IASContext context, ASExpr expr, int lineNum, ref string closestListName, ref string closestListItemType) { + if (expr?.LocalVars is null) return; MemberModel closestList = null; - if (expr == null || expr.LocalVars == null) - return; - - foreach (MemberModel m in expr.LocalVars) + foreach (var m in expr.LocalVars) { - if (m.LineFrom > lineNum) - continue; - if (closestList != null && m.LineFrom <= closestList.LineFrom) - continue; - - ClassModel aType2 = ASContext.Context.ResolveType(m.Type, context.CurrentModel); - string objType = ASContext.Context.Features.objectKey; + if (m.LineFrom > lineNum) continue; + if (closestList != null && m.LineFrom <= closestList.LineFrom) continue; + var aType2 = ResolveType(m.Type, context.CurrentModel); + var objType = ASContext.Context.Features.objectKey; while (!aType2.IsVoid() && aType2.QualifiedName != objType) { if (aType2.IndexType != null) @@ -1099,15 +1013,14 @@ public static void FindClosestList(IASContext context, ASExpr expr, int lineNum, public static string FindFreeIterator(IASContext context, ClassModel cClass, ASExpr expr) { - int iteratorCount = 105; - string iterator = ((char)iteratorCount).ToString(); - bool restartCycle = false; - MemberList members = cClass.Members; - List parameters = context.CurrentMember.Parameters; + var iteratorCount = 105; + var iterator = ((char)iteratorCount).ToString(); + var members = cClass.Members; + var parameters = context.CurrentMember.Parameters; while (true) { - restartCycle = false; - if (expr != null && expr.LocalVars != null) + var restartCycle = false; + if (expr?.LocalVars != null) foreach (MemberModel m in expr.LocalVars) { if (m.Name == iterator) @@ -1150,59 +1063,59 @@ public static string FindFreeIterator(IASContext context, ClassModel cClass, ASE return iterator; } - private static string GetKind(FlagType flags, ContextFeatures features) + static string GetKind(FlagType flags, ContextFeatures features) { if (flags == FlagType.Function) return features.functionKey; if ((flags & FlagType.Constant) > 0) return features.constKey; if ((flags & (FlagType.Getter | FlagType.Setter)) > 0) return features.varKey; - if ((flags & FlagType.Interface) > 0) return "interface"; - if ((flags & FlagType.Class) > 0) return "class"; - return ""; + if ((flags & FlagType.Interface) > 0) return features.InterfaceKey; + if ((flags & FlagType.Class) > 0) return features.ClassKey; + return string.Empty; } #endregion #region structure_completion - static private void HandleStructureCompletion(ScintillaControl Sci) + + static void HandleStructureCompletion(ScintillaControl sci) { try { - int position = Sci.CurrentPos; - int line = Sci.LineFromPosition(position); - if (line == 0) - return; - string txt = Sci.GetLine(line - 1).TrimEnd(); - int style = Sci.BaseStyleAt(position); + int position = sci.CurrentPos; + int line = sci.LineFromPosition(position); + if (line == 0) return; + string txt = sci.GetLine(line - 1).TrimEnd(); + int style = sci.BaseStyleAt(position); // move closing brace to its own line and fix indentation - if (Sci.CurrentChar == '}') + if (sci.CurrentChar == '}') { - var openingBrace = Sci.SafeBraceMatch(position); - var openLine = openingBrace >= 0 ? Sci.LineFromPosition(openingBrace) : line - 1; - Sci.InsertText(Sci.CurrentPos, LineEndDetector.GetNewLineMarker(Sci.EOLMode)); - Sci.SetLineIndentation(line + 1, Sci.GetLineIndentation(openLine)); + var openingBrace = sci.SafeBraceMatch(position); + var openLine = openingBrace >= 0 ? sci.LineFromPosition(openingBrace) : line - 1; + sci.InsertText(sci.CurrentPos, LineEndDetector.GetNewLineMarker(sci.EOLMode)); + sci.SetLineIndentation(line + 1, sci.GetLineIndentation(openLine)); } // in comments else if (PluginBase.Settings.CommentBlockStyle == CommentBlockStyle.Indented && txt.EndsWithOrdinal("*/")) - FixIndentationAfterComments(Sci, line); - else if (IsCommentStyle(style) && (Sci.BaseStyleAt(position + 1) == style)) - FormatComments(Sci, txt, line); + FixIndentationAfterComments(sci, line); + else if (IsCommentStyle(style) && (sci.BaseStyleAt(position + 1) == style)) + FormatComments(sci, txt, line); // in code else { // braces if (!ASContext.CommonSettings.DisableAutoCloseBraces) { - if (txt.IndexOfOrdinal("//") > 0) // remove comment at end of line + if (txt.Contains("//", out var p1) && p1 > 0) // remove comment at end of line { - int slashes = Sci.MBSafeTextLength(txt.Substring(0, txt.IndexOfOrdinal("//") + 1)); - if (Sci.PositionIsOnComment(Sci.PositionFromLine(line-1) + slashes)) - txt = txt.Substring(0, txt.IndexOfOrdinal("//")).Trim(); + var slashes = sci.MBSafeTextLength(txt.Substring(0, p1 + 1)); + if (sci.PositionIsOnComment(sci.PositionFromLine(line-1) + slashes)) + txt = txt.Substring(0, p1).Trim(); } - if (txt.EndsWith('{') && (line > 1)) AutoCloseBrace(Sci, line); + if (txt.EndsWith('{') && line > 1) AutoCloseBrace(sci, line); } // code reformatting if (!ASContext.CommonSettings.DisableCodeReformat && !txt.EndsWithOrdinal("*/")) - ReformatLine(Sci, Sci.PositionFromLine(line) - 1); + ReformatLine(sci, sci.PositionFromLine(line) - 1); } } catch (Exception ex) @@ -1211,36 +1124,40 @@ static private void HandleStructureCompletion(ScintillaControl Sci) } } - private static void ReformatLine(ScintillaControl sci, int position) + static void ReformatLine(ScintillaControl sci, int position) { int line = sci.LineFromPosition(position); string txt = sci.GetLine(line).TrimEnd('\r', '\n'); int curPos = sci.CurrentPos; int startPos = sci.PositionFromLine(line); int offset = sci.MBSafeLengthFromBytes(txt, position - startPos); - - ReformatOptions options = new ReformatOptions(); - options.Newline = LineEndDetector.GetNewLineMarker(sci.EOLMode); - options.CondenseWhitespace = ASContext.CommonSettings.CondenseWhitespace; - options.BraceAfterLine = ASContext.CommonSettings.ReformatBraces - && PluginBase.MainForm.Settings.CodingStyle == CodingStyle.BracesAfterLine; - options.CompactChars = ASContext.CommonSettings.CompactChars; - options.SpacedChars = ASContext.CommonSettings.SpacedChars; - options.SpaceBeforeFunctionCall = ASContext.CommonSettings.SpaceBeforeFunctionCall; - options.AddSpaceAfter = ASContext.CommonSettings.AddSpaceAfter.Split(' '); - options.IsPhp = ASContext.Context.Settings.LanguageId == "PHP"; - options.IsHaXe = ASContext.Context.Settings.LanguageId == "HAXE"; + var options = new ReformatOptions + { + Newline = LineEndDetector.GetNewLineMarker(sci.EOLMode), + CondenseWhitespace = ASContext.CommonSettings.CondenseWhitespace, + BraceAfterLine = ASContext.CommonSettings.ReformatBraces && PluginBase.Settings.CodingStyle == CodingStyle.BracesAfterLine, + CompactChars = ASContext.CommonSettings.CompactChars, + SpacedChars = ASContext.CommonSettings.SpacedChars, + SpaceBeforeFunctionCall = ASContext.CommonSettings.SpaceBeforeFunctionCall, + AddSpaceAfter = !string.IsNullOrEmpty(ASContext.Context.Settings.AddSpaceAfter) + ? ASContext.Context.Settings.AddSpaceAfter.Split(' ') + : ASContext.CommonSettings.AddSpaceAfter.Split(' '), + IsPhp = ASContext.Context.Settings.LanguageId == "PHP", + IsHaXe = ASContext.Context.Settings.LanguageId == "HAXE" + }; if (options.IsHaXe) { var initialStyle = sci.BaseStyleAt(startPos); - if (initialStyle == 6) options.InString = 1; - else if (initialStyle == 7) options.InString = 2; + options.InString = initialStyle switch + { + (int) CPP.STRING => 1, + (int) CPP.CHARACTER => 2, + _ => options.InString + }; } - int newOffset = offset; - string replace = Reformater.ReformatLine(txt, options, ref newOffset); - + var replace = Reformater.ReformatLine(txt, options, ref newOffset); if (replace != txt) { position = curPos + newOffset - offset; @@ -1248,84 +1165,80 @@ private static void ReformatLine(ScintillaControl sci, int position) sci.ReplaceSel(replace); sci.SetSel(position, position); } - } - + } + /// /// Add closing brace to a code block. /// If enabled, move the starting brace to a new line. /// - /// - /// + /// /// - private static void AutoCloseBrace(ScintillaControl Sci, int line) + static void AutoCloseBrace(ScintillaControl sci, int line) { // find matching brace - int bracePos = Sci.LineEndPosition(line - 1) - 1; - while ((bracePos > 0) && (Sci.CharAt(bracePos) != '{')) bracePos--; - if (bracePos == 0 || Sci.BaseStyleAt(bracePos) != 10) return; - int match = Sci.SafeBraceMatch(bracePos); + int bracePos = sci.LineEndPosition(line - 1) - 1; + while ((bracePos > 0) && (sci.CharAt(bracePos) != '{')) bracePos--; + if (bracePos == 0 || sci.BaseStyleAt(bracePos) != 10) return; + int match = sci.SafeBraceMatch(bracePos); int start = line; - int indent = Sci.GetLineIndentation(start - 1); + int indent = sci.GetLineIndentation(start - 1); if (match > 0) { - int endIndent = Sci.GetLineIndentation(Sci.LineFromPosition(match)); - if (endIndent + Sci.TabWidth > indent) + int endIndent = sci.GetLineIndentation(sci.LineFromPosition(match)); + if (endIndent + sci.TabWidth > indent) return; } // find where to include the closing brace int startIndent = indent; - int count = Sci.LineCount; + int count = sci.LineCount; int lastLine = line; int position; - string txt = Sci.GetLine(line).Trim(); + string txt = sci.GetLine(line).Trim(); line++; - int eolMode = Sci.EOLMode; + int eolMode = sci.EOLMode; string NL = LineEndDetector.GetNewLineMarker(eolMode); - if (txt.Length > 0 && ")]};,".IndexOf(txt[0]) >= 0) + if (txt.Length > 0 && ")]};,".Contains(txt[0])) { - Sci.BeginUndoAction(); + sci.BeginUndoAction(); try { - position = Sci.CurrentPos; - Sci.InsertText(position, NL + "}"); - Sci.SetLineIndentation(line, startIndent); + position = sci.CurrentPos; + sci.InsertText(position, NL + "}"); + sci.SetLineIndentation(line, startIndent); } finally { - Sci.EndUndoAction(); + sci.EndUndoAction(); } return; } - else + while (line < count - 1) { - while (line < count - 1) + txt = sci.GetLine(line).TrimEnd(); + if (txt.Length != 0) { - txt = Sci.GetLine(line).TrimEnd(); - if (txt.Length != 0) - { - indent = Sci.GetLineIndentation(line); - if (indent <= startIndent) break; - lastLine = line; - } - else break; - line++; + indent = sci.GetLineIndentation(line); + if (indent <= startIndent) break; + lastLine = line; } + else break; + line++; } if (line >= count - 1) lastLine = start; // insert closing brace - Sci.BeginUndoAction(); + sci.BeginUndoAction(); try { - position = Sci.LineEndPosition(lastLine); - Sci.InsertText(position, NL + "}"); - Sci.SetLineIndentation(lastLine + 1, startIndent); + position = sci.LineEndPosition(lastLine); + sci.InsertText(position, NL + "}"); + sci.SetLineIndentation(lastLine + 1, startIndent); } finally { - Sci.EndUndoAction(); + sci.EndUndoAction(); } } @@ -1333,61 +1246,62 @@ private static void AutoCloseBrace(ScintillaControl Sci, int line) /// When javadoc comment blocks have and additional space, /// fix indentation of new line following this block /// - /// + /// /// - private static void FixIndentationAfterComments(ScintillaControl Sci, int line) + static void FixIndentationAfterComments(ScintillaControl sci, int line) { int startLine = line - 1; while (startLine > 0) { - string txt = Sci.GetLine(startLine).TrimStart(); + string txt = sci.GetLine(startLine).TrimStart(); if (txt.StartsWithOrdinal("/*")) break; - else if (!txt.StartsWith('*')) break; + if (!txt.StartsWith('*')) break; startLine--; } - Sci.SetLineIndentation(line, Sci.GetLineIndentation(startLine)); - int position = Sci.LineIndentPosition(line); - Sci.SetSel(position, position); + sci.SetLineIndentation(line, sci.GetLineIndentation(startLine)); + int position = sci.LineIndentPosition(line); + sci.SetSel(position, position); } /// /// Add a '*' at the beginning of new lines inside a comment block /// - /// + /// /// /// - private static void FormatComments(ScintillaControl Sci, string txt, int line) + static void FormatComments(ScintillaControl sci, string txt, int line) { txt = txt.TrimStart(); if (txt.StartsWithOrdinal("/*")) { - Sci.ReplaceSel("* "); + sci.ReplaceSel("* "); if (PluginBase.Settings.CommentBlockStyle == CommentBlockStyle.Indented) - Sci.SetLineIndentation(line, Sci.GetLineIndentation(line) + 1); - int position = Sci.LineIndentPosition(line) + 2; - Sci.SetSel(position, position); + sci.SetLineIndentation(line, sci.GetLineIndentation(line) + 1); + int position = sci.LineIndentPosition(line) + 2; + sci.SetSel(position, position); } else if (txt.StartsWith('*')) { - Sci.ReplaceSel("* "); - int position = Sci.LineIndentPosition(line) + 2; - Sci.SetSel(position, position); + sci.ReplaceSel("* "); + int position = sci.LineIndentPosition(line) + 2; + sci.SetSel(position, position); } } #endregion #region template_completion - static private bool HandleDeclarationCompletion(ScintillaControl Sci, string tail, bool autoHide) + + static bool HandleDeclarationCompletion(ScintillaControl sci, string tail, bool autoHide) { - int position = Sci.CurrentPos; - int line = Sci.LineFromPosition(position); - if (Sci.CharAt(position - 1) <= 32) tail = ""; + int position = sci.CurrentPos; + int line = sci.LineFromPosition(position); + if (sci.CharAt(position - 1) <= ' ') tail = ""; // completion support - IASContext ctx = ASContext.Context; - ContextFeatures features = ctx.Features; - bool insideClass = !ctx.CurrentClass.IsVoid() && ctx.CurrentClass.LineFrom < line; - List support = features.GetDeclarationKeywords(Sci.GetLine(line), insideClass); + var ctx = ASContext.Context; + var features = ctx.Features; + var insideClass = !ctx.CurrentClass.IsVoid() && ctx.CurrentClass.LineFrom < line; + var support = features.GetDeclarationKeywords(sci.GetLine(line), insideClass); if (support.Count == 0) return true; // does it need indentation? @@ -1395,63 +1309,45 @@ static private bool HandleDeclarationCompletion(ScintillaControl Sci, string tai int tempLine = line-1; while (tempLine > 0) { - var tempText = Sci.GetLine(tempLine).Trim(); + var tempText = sci.GetLine(tempLine).Trim(); if (insideClass && CodeUtils.IsTypeDecl(tempText, features.typesKeywords)) { - tab = Sci.GetLineIndentation(tempLine) + Sci.TabWidth; + tab = sci.GetLineIndentation(tempLine) + sci.TabWidth; break; } - if (tempText.Length > 0 && (tempText.EndsWith("}") || CodeUtils.IsDeclaration(tempText, features))) + if (tempText.Length > 0 && (tempText.EndsWith('}') || CodeUtils.IsDeclaration(tempText, features))) { - tab = Sci.GetLineIndentation(tempLine); - if (tempText.EndsWith('{')) tab += Sci.TabWidth; + tab = sci.GetLineIndentation(tempLine); + if (tempText.EndsWith('{')) tab += sci.TabWidth; break; } tempLine--; } - if (tab > 0) - { - Sci.SetLineIndentation(line, tab); - } - - // build list - List known = new List(); - foreach(string token in support) - known.Add(new DeclarationItem(token)); - - // show - CompletionList.Show(known, autoHide, tail); + if (tab > 0) sci.SetLineIndentation(line, tab); + var list = support.Select(static it => new DeclarationItem(it)).ToArray(); + CompletionList.Show(list, autoHide, tail); return true; } #endregion #region function_completion - static private string calltipDef; - static private MemberModel calltipMember; - static private bool calltipDetails; - static private int calltipPos = -1; - static private int calltipOffset; - static private ClassModel calltipRelClass; - static private string prevParam = ""; - static private string paramInfo = ""; - - static public bool HasCalltip() - { - return UITools.CallTip.CallTipActive && (calltipDef != null); - } + internal static string calltipDef; + protected static MemberModel calltipMember; + static bool calltipDetails; + static int calltipPos = -1; + static int calltipOffset; + static ClassModel calltipRelClass; + static string prevParam = ""; + + public static bool HasCalltip() => UITools.CallTip.CallTipActive && (calltipDef != null); /// /// Show highlighted calltip /// - /// Scintilla control - /// Highlight param number - static private void ShowCalltip(ScintillaControl sci, int paramNumber) - { - ShowCalltip(sci, paramNumber, false); - } - - static private void ShowCalltip(ScintillaControl sci, int paramIndex, bool forceRedraw) + /// Scintilla control + /// Highlight param number + static void ShowCalltip(ScintillaControl sci, int paramIndex) { // measure highlighting int start = calltipDef.IndexOf('('); @@ -1475,27 +1371,16 @@ static private void ShowCalltip(ScintillaControl sci, int paramIndex, bool force p = paramName.IndexOf('='); if (p > 0) paramName = paramName.Substring(0, p); } - char[] toClean = new char[] { ' ', '\t', '\n', '\r', '*', '?' }; - paramName = paramName.Trim(toClean); - - if (paramName.Length > 0) - { - Match mParam = Regex.Match(calltipMember.Comments, "@param\\s+" + Regex.Escape(paramName) + "[ \t:]+(?[^\r\n]*)"); - if (mParam.Success) - paramInfo = "\n" + "[U]" + paramName + ":" + "[/U]" + mParam.Groups["desc"].Value.Trim(); - else - paramInfo = ""; - } - else paramInfo = ""; + paramName = paramName.Trim(' ', '\t', '\n', '\r', '*', '?'); } - + // show calltip if (!UITools.CallTip.CallTipActive || UITools.Manager.ShowDetails != calltipDetails || paramName != prevParam) { prevParam = paramName; calltipDetails = UITools.Manager.ShowDetails; string text = calltipDef + ASDocumentation.GetTipDetails(calltipMember, paramName); - UITools.CallTip.CallTipShow(sci, calltipPos - calltipOffset, text, forceRedraw); + UITools.CallTip.CallTipShow(sci, calltipPos - calltipOffset, text); } // highlight @@ -1503,15 +1388,13 @@ static private void ShowCalltip(ScintillaControl sci, int paramIndex, bool force else UITools.CallTip.CallTipSetHlt(start + 1, end, true); } - static private int FindNearSymbolInFunctDef(string defBody, char symbol, int startAt) + static int FindNearSymbolInFunctDef(string defBody, char symbol, int startAt) { string featEnd = null; - for (int i = startAt, count = defBody.Length; i < count; i++) { char c = defBody[i]; - - if (featEnd == null) + if (featEnd is null) { switch (c) { @@ -1579,172 +1462,151 @@ static private int FindNearSymbolInFunctDef(string defBody, char symbol, int sta featEnd = null; } } - return -1; } /// /// Display method signature /// - /// Scintilla control + /// Scintilla control + /// Auto-started completion (is false when pressing Ctrl+Space) /// Auto-completion has been handled - static public bool HandleFunctionCompletion(ScintillaControl Sci, bool autoHide) - { - return HandleFunctionCompletion(Sci, autoHide, false); - } - - static public bool HandleFunctionCompletion(ScintillaControl Sci, bool autoHide, bool forceRedraw) + public static bool HandleFunctionCompletion(ScintillaControl sci, bool autoHide) { // only auto-complete where it makes sense - if (DeclarationSectionOnly()) - return false; - - int position = Sci.CurrentPos - 1; - int paramIndex = FindParameterIndex(Sci, ref position); + if (DeclarationSectionOnly()) return false; + var position = sci.CurrentPos - 1; + var paramIndex = FindParameterIndex(sci, ref position); if (position < 0) return false; - // continuing calltip ? if (HasCalltip()) { if (calltipPos == position) { - ShowCalltip(Sci, paramIndex, forceRedraw); + ShowCalltip(sci, paramIndex); return true; } - else UITools.CallTip.Hide(); + UITools.CallTip.Hide(); } - - if (!ResolveFunction(Sci, position, autoHide)) - return true; - + if (!ASContext.Context.CodeComplete.ResolveFunction(sci, position, autoHide)) return true; // EventDispatchers if (paramIndex == 0 && calltipRelClass != null && calltipMember.Name.EndsWithOrdinal("EventListener")) { - ShowListeners(Sci, position, calltipRelClass); + ShowListeners(sci, position, calltipRelClass); return true; } - // show calltip - ShowCalltip(Sci, paramIndex, forceRedraw); + ShowCalltip(sci, paramIndex); return true; } /// /// Find declaration of function called in code /// + /// Scintilla control /// Position obtained by FindParameterIndex() + /// Auto-started completion (is false when pressing Ctrl+Space) /// Function successfully resolved - private static bool ResolveFunction(ScintillaControl Sci, int position, bool autoHide) + protected internal bool ResolveFunction(ScintillaControl sci, int position, bool autoHide) { calltipPos = 0; calltipMember = null; calltipRelClass = null; - + var ctx = ASContext.Context; // get expression at cursor position - ASExpr expr = GetExpression(Sci, position, true); - if (string.IsNullOrEmpty(expr.Value) - || (expr.WordBefore == "function" && expr.Separator == " ")) + var expr = GetExpression(sci, position, true); + if (string.IsNullOrEmpty(expr.Value) || (expr.WordBefore == ctx.Features.functionKey && expr.Separator == " ")) return false; - - // Context - IASContext ctx = ASContext.Context; - FileModel aFile = ctx.CurrentModel; - ClassModel aClass = ctx.CurrentClass; - ASResult result; - // Expression before cursor expr.LocalVars = ParseLocalVars(expr); - result = EvalExpression(expr.Value, expr, aFile, aClass, true, true); - if (!result.IsNull() && result.Member == null && result.Type != null) - { - foreach(MemberModel member in result.Type.Members) - if (member.Name == result.Type.Constructor) - { - result.Member = member; - break; - } - } - if (result.IsNull() || (result.Member != null && (result.Member.Flags & FlagType.Function) == 0)) + var result = EvalExpression(expr.Value, expr, ctx.CurrentModel, ctx.CurrentClass, true, true); + if (result.Member is null && result.Type != null) + result.Member = result.Type.SearchMember(result.Type.Constructor, true); + return ResolveFunction(sci, position, result, autoHide); + } + + /// + /// Find declaration of function called in code + /// + /// Scintilla control + /// Position obtained by FindParameterIndex() + /// Expression before cursor + /// Auto-started completion (is false when pressing Ctrl+Space) + /// Function successfully resolved + protected virtual bool ResolveFunction(ScintillaControl sci, int position, ASResult expr, bool autoHide) + { + var ctx = ASContext.Context; + if (expr.IsNull() || (expr.Member != null && (expr.Member.Flags & FlagType.Function) == 0)) { // custom completion - MemberModel customMethod = ctx.ResolveFunctionContext(Sci, expr, autoHide); - if (customMethod != null) - { - result = new ASResult(); - result.Member = customMethod; - } + var customMethod = ctx.ResolveFunctionContext(sci, expr.Context, autoHide); + if (customMethod != null) expr = new ASResult {Member = customMethod, Context = new ASExpr()}; } - if (result.IsNull()) + if (expr.IsNull()) return false; - MemberModel method = result.Member; - if (method == null) + var method = expr.Member; + if (method is null) { - if (result.Type == null) - return false; - string constructor = ASContext.GetLastStringToken(result.Type.Name, "."); - result.Member = method = result.Type.Members.Search(constructor, FlagType.Constructor, 0); - if (method == null) - return false; + if (expr.Type is null) return false; + var constructor = ASContext.GetLastStringToken(expr.Type.Name, "."); + expr.Member = method = expr.Type.Members.Search(constructor, FlagType.Constructor); + if (method is null) return false; } else if ((method.Flags & FlagType.Function) == 0) { - if (method.Name == "super" && result.Type != null) + if (method.Name == "super" && expr.Type != null) { - result.Member = method = result.Type.Members.Search(result.Type.Constructor, FlagType.Constructor, 0); - if (method == null) - return false; + expr.Member = method = expr.Type.Members.Search(expr.Type.Constructor, FlagType.Constructor); + if (method is null) return false; } else return false; } // inherit doc - while ((method.Flags & FlagType.Override) > 0 && result.InClass != null - && (method.Comments == null || method.Comments.Trim() == "" || method.Comments.Contains("@inheritDoc"))) + while ((method.Flags & FlagType.Override) > 0 && expr.InClass != null + && (method.Comments is null || method.Comments.Trim().Length == 0 || method.Comments.Contains("@inheritDoc"))) { - FindMember(method.Name, result.InClass.Extends, result, 0, 0); - method = result.Member; - if (method == null) - return false; + FindMember(method.Name, expr.InClass.Extends, expr, 0, 0); + method = expr.Member; + if (method is null) return false; } - if ((method.Comments == null || method.Comments.Trim() == "") - && result.InClass != null && result.InClass.Implements != null) + if ((method.Comments is null || method.Comments.Trim().Length == 0) && expr.InClass?.Implements != null) { - ASResult iResult = new ASResult(); - foreach (string type in result.InClass.Implements) + var iResult = new ASResult(); + foreach (var type in expr.InClass.Implements) { - ClassModel model = ASContext.Context.ResolveType(type, result.InFile); + var model = ResolveType(type, expr.InFile); FindMember(method.Name, model, iResult, 0, 0); if (iResult.Member != null) { - iResult.RelClass = result.RelClass; - result = iResult; + iResult.RelClass = expr.RelClass; + iResult.Context = expr.Context; + expr = iResult; method = iResult.Member; break; } } } - - expr.Position = position; - FunctionContextResolved(Sci, expr, method, result.RelClass, false); + expr.Context.Position = position; + FunctionContextResolved(sci, expr.Context, method, expr.RelClass, false); return true; } public static void FunctionContextResolved(ScintillaControl sci, ASExpr expr, MemberModel method, ClassModel inClass, bool showTip) { - if (string.IsNullOrEmpty(method?.Name)) - return; + if (string.IsNullOrEmpty(method?.Name)) return; if (calltipMember != null && calltipMember.Name == method.Name) { // use FD-extracted comments - if (method.Comments == null && !string.IsNullOrEmpty(calltipMember.Comments)) + if (method.Comments is null && !string.IsNullOrEmpty(calltipMember.Comments)) method.Comments = calltipMember.Comments; } int position = expr.Position; calltipPos = position; calltipOffset = Math.Min(expr.Value.Length, method.Name.Length); - calltipDef = method.ToString(); + calltipDef = ASContext.Context.CodeComplete.GetCalltipDef(method); calltipMember = method; calltipDetails = UITools.Manager.ShowDetails; calltipRelClass = inClass; @@ -1752,106 +1614,140 @@ public static void FunctionContextResolved(ScintillaControl sci, ASExpr expr, Me if (showTip) { - position = sci.CurrentPos - 1; + position = sci.CurrentPos - 1; sci.Colourise(0, -1); - int paramIndex = FindParameterIndex(sci, ref position); + var paramIndex = FindParameterIndex(sci, ref position); if (position < 0) return; - ShowCalltip(sci, paramIndex, true); + ShowCalltip(sci, paramIndex); } } + public virtual MemberModel FunctionTypeToMemberModel(string type, FileModel inFile) => null; + + protected virtual string GetCalltipDef(MemberModel member) => member.ToString(); + /// /// Find type of current parameter in current function call /// /// /// Resolve only if parameter is an Object with an index type /// - private static ClassModel ResolveParameterType(int paramIndex, bool indexTypeOnly) + static ClassModel ResolveParameterType(int paramIndex, bool indexTypeOnly) { - if (calltipMember != null && calltipMember.Parameters != null - && paramIndex < calltipMember.Parameters.Count) - { - MemberModel param = calltipMember.Parameters[paramIndex]; - string type = param.Type; - if (indexTypeOnly && (String.IsNullOrEmpty(type) || type.IndexOf('@') < 0)) - return ClassModel.VoidClass; - if (ASContext.Context.Features.objectKey == "Dynamic" && type.StartsWithOrdinal("Dynamic@")) - type = type.Replace("Dynamic@", "Dynamic<") + ">"; - return ASContext.Context.ResolveType(type, ASContext.Context.CurrentModel); - } - else return ClassModel.VoidClass; + if (calltipMember?.Parameters is null || paramIndex >= calltipMember.Parameters.Count) return ClassModel.VoidClass; + var type = calltipMember.Parameters[paramIndex].Type; + if (indexTypeOnly && (string.IsNullOrEmpty(type) || !type.Contains('@'))) return ClassModel.VoidClass; + if (ASContext.Context.Features.objectKey == "Dynamic" && type.StartsWithOrdinal("Dynamic@")) + type = type.Replace("Dynamic@", "Dynamic<") + ">"; + return ResolveType(type, ASContext.Context.CurrentModel); } /// /// Locate beginning of function call parameters and return index of current parameter /// - internal static int FindParameterIndex(ScintillaControl sci, ref int position) + protected internal static int FindParameterIndex(ScintillaControl sci, ref int position) { - int parCount = 0; - int braCount = 0; - int comaCount = 0; - int arrCount = 0; + var characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; + var ctx = ASContext.Context; + var parCount = 0; + var braCount = 0; + var comaCount = 0; + var arrCount = 0; var genCount = 0; - while (position >= 0) + var hasChar = false; + var endPosition = ctx.CurrentMember != null ? sci.LineEndPosition(ctx.CurrentMember.LineFrom - 1) : 0; + while (position >= endPosition) { - var style = sci.BaseStyleAt(position); - if ((!IsLiteralStyle(style) && IsTextStyleEx(style)) || IsInterpolationExpr(sci, position)) + if (sci.PositionIsOnComment(position)) { - var c = (char)sci.CharAt(position); - if (c <= ' ') + position--; + continue; + } + var c = (char) sci.CharAt(position); + // skip {} () [] "" '' blocks + if (((braCount > 0 && c != '{' && c != '}') + || (parCount > 0 && c != '(' && c != ')') + || (arrCount > 0 && c != '[' && c != ']')) + || (sci.PositionIsInString(position) && !ctx.CodeComplete.IsStringInterpolationStyle(sci, position))) + { + position--; + continue; + } + if (c <= ' ') + { + position--; + continue; + } + if (parCount < 0) + { + if (characterClass.Contains(c) || c == '>' || c == ']' || c == ')') { - position--; - continue; + position++; + break; // function start found } - // skip {} () [] blocks - if ((braCount > 0 && c != '{' && c != '}') - || (parCount > 0 && c != '(' && c != ')') - || (arrCount > 0 && c != '[' && c != ']')) + if (char.IsPunctuation(c) || char.IsSymbol(c)) parCount = 0; + } + else if (c == ';' && braCount == 0) + { + position = -1; + break; + } + if (c == '}') braCount++; + else if (c == ']') arrCount++; + else if (c == ')') parCount++; + else if (c == '{') + { + if (braCount == 0) comaCount = 0; + else braCount--; + } + else if (c == '[') + { + if (arrCount == 0) comaCount = 0; + else arrCount--; + } + else if (c == '(') --parCount; + else if (c == '?' && genCount > 0) genCount = 0; + else if (c == '>') + { + // for example: -> + if (position - 1 >= endPosition && sci.CharAt(position - 1) == '-') { - position--; + position -= 2; continue; } - if (c == ';' && braCount == 0) - { - position = -1; - break; - } - // new block - else if (c == '}') braCount++; - else if (c == ']') arrCount++; - else if (c == ')') parCount++; - // block closed - else if (c == '{') - { - if (braCount == 0) comaCount = 0; - else braCount--; - } - else if (c == '[') + if (hasChar) { - if (arrCount == 0) comaCount = 0; - else arrCount--; + position--; + continue; } - else if (c == '(') + genCount++; + } + else if (c == '<') + { + if (hasChar) { - if (--parCount < 0) - // function start found - break; + position--; + continue; } - else if (c == '>') genCount++; - else if (c == '<') genCount--; - // new parameter reached - else if (c == ',' && parCount == 0 && genCount == 0) - comaCount++; + if (genCount > 0) genCount--; + } + // new parameter reached + else if (c == ',') + { + parCount = 0; + if (genCount == 0) comaCount++; + hasChar = false; } + else if (characterClass.Contains(c)) hasChar = true; position--; } return comaCount; } - private static void ShowListeners(ScintillaControl Sci, int position, ClassModel ofClass) + static void ShowListeners(ScintillaControl sci, int position, ClassModel ofClass) { // find event metadatas - List events = new List(); + var events = new List(); while (ofClass != null && !ofClass.IsVoid()) { if (ofClass.MetaDatas != null) @@ -1865,28 +1761,22 @@ private static void ShowListeners(ScintillaControl Sci, int position, ClassModel // format events.Sort(); - Dictionary eventTypes = new Dictionary(); - List list = new List(); - foreach (ASMetaData meta in events) - { - string name = meta.Params["name"]; - Regex reName = new Regex("[\"']" + name + "[\"']"); - string type = meta.Params["type"]; - string comments = meta.Comments; - FlagType flags = FlagType.Variable | FlagType.Constant; - Visibility acc = Visibility.Public; + var eventTypes = new Dictionary(); + var list = new List(); + foreach (var meta in events) + { + var name = meta.Params["name"]; + var reName = new Regex("[\"']" + name + "[\"']"); + var type = meta.Params["type"]; + var comments = meta.Comments; if (name.Length > 0 && type.Length > 0) { - ClassModel evClass; - if (!eventTypes.ContainsKey(type)) + if (!eventTypes.TryGetValue(type, out var evClass)) { - evClass = ASContext.Context.ResolveType(type.Replace(':', '.'), null); + evClass = ResolveType(type.Replace(':', '.'), null); eventTypes.Add(type, evClass); } - else evClass = eventTypes[type]; - if (evClass.IsVoid()) - continue; - + if (evClass.IsVoid()) continue; bool typeFound = false; foreach (MemberModel member in evClass.Members) { @@ -1894,9 +1784,7 @@ private static void ShowListeners(ScintillaControl Sci, int position, ClassModel { typeFound = true; name = evClass.Name + '.' + member.Name; - flags = member.Flags; - acc = member.Access; - if (meta.Comments == null && member.Comments != null) + if (meta.Comments is null && member.Comments != null) comments = member.Comments; break; } @@ -1914,18 +1802,18 @@ private static void ShowListeners(ScintillaControl Sci, int position, ClassModel // filter list.Sort(new CompletionItemComparer()); - List items = new List(); + var items = new List(list.Count); string prev = null; - foreach (ICompletionListItem item in list) + foreach (var item in list) { if (item.Label != prev) items.Add(item); prev = item.Label; } // display - Sci.SetSel(position + 1, Sci.CurrentPos); - string tail = Sci.SelText; - Sci.SetSel(Sci.SelectionEnd, Sci.SelectionEnd); + sci.SetSel(position + 1, sci.CurrentPos); + var tail = sci.SelText; + sci.SetSel(sci.SelectionEnd, sci.SelectionEnd); CompletionList.Show(items, true, tail); } @@ -1935,52 +1823,60 @@ private static void ShowListeners(ScintillaControl Sci, int position, ClassModel /// /// Complete object member /// - /// Scintilla control + /// Scintilla control + /// Don't keep the list open if the word does not match + /// Auto-completion has been handled + static bool HandleDotCompletion(ScintillaControl sci, bool autoHide) + => ASContext.Context.CodeComplete.HandleDotCompletion(sci, autoHide, null, null); + + /// + /// Complete object member + /// + /// Scintilla control /// Don't keep the list open if the word does not match + /// + /// /// Auto-completion has been handled - static private bool HandleDotCompletion(ScintillaControl Sci, bool autoHide) + protected bool HandleDotCompletion(ScintillaControl sci, bool autoHide, List list, Comparison comparison) { //this method can exit at multiple points, so reset the current class now rather than later currentClassHash = null; // only auto-complete where it makes sense - if (autoHide && DeclarationSectionOnly()) - return false; + if (autoHide && DeclarationSectionOnly()) return false; - // get expression at cursor position - int position = Sci.CurrentPos; - ASExpr expr = GetExpression(Sci, position); - if (expr.Value == null) - return true; - IASContext ctx = ASContext.Context; - ContextFeatures features = ctx.Features; - int dotIndex = expr.Value.LastIndexOfOrdinal(features.dot); - if (dotIndex == 0 && expr.Separator != "\"") - return true; + var position = sci.CurrentPos; + var expr = GetExpression(sci, position); + if (expr.Value is null) return true; + // for example: expr;.$(EntryPoint) + if (expr.Value.Length == 0 && sci.CharAt(position - 1) == '.') return false; + var ctx = ASContext.Context; + var features = ctx.Features; + var dotIndex = expr.Value.LastIndexOfOrdinal(features.dot); + if (dotIndex == 0 && expr.Separator != "\"") return true; // complete keyword - string word = expr.WordBefore; - if (word != null && Array.IndexOf(features.declKeywords, word) >= 0) - return false; + var word = expr.WordBefore; + if (!word.IsNullOrEmpty() && features.declKeywords.Contains(word)) return false; ClassModel argumentType = null; if (dotIndex < 0) { - if (word != null) + if (!word.IsNullOrEmpty()) { - if (word == "class" || word == "package" || word == "interface" || word == "catch") + if (word == features.ClassKey || word == features.PackageKey || word == features.InterfaceKey || word == "catch") return false; if (features.hasInference && word == "for") // haxe doesn't have 'var' in for() return false; // new/extends/implements if (features.HasTypePreKey(word)) - return HandleNewCompletion(Sci, expr.Value, autoHide, word); + return HandleNewCompletion(sci, expr.Value, autoHide, word); // import if (features.hasImports && (word == features.importKey || word == features.importKeyAlt)) - return HandleImportCompletion(Sci, expr.Value, autoHide); + return HandleImportCompletion(sci, expr.Value, autoHide); + if (word == features.overrideKey) return HandleOverrideCompletion(expr.Value, autoHide); } // type - else if (features.hasEcmaTyping && expr.Separator == ":" - && HandleColonCompletion(Sci, expr.Value, autoHide)) + else if (features.hasEcmaTyping && expr.Separator == ":" && HandleColonCompletion(sci, expr.Value, autoHide)) return true; // no completion @@ -1991,104 +1887,86 @@ static private bool HandleDotCompletion(ScintillaControl Sci, bool autoHide) if (expr.coma == ComaExpression.AnonymousObjectParam) { - int cpos = Sci.CurrentPos - 1; - int paramIndex = FindParameterIndex(Sci, ref cpos); - if (calltipPos != cpos) ResolveFunction(Sci, cpos, autoHide); - if (calltipMember == null) return false; + var cpos = sci.CurrentPos - 1; + var paramIndex = FindParameterIndex(sci, ref cpos); + if (calltipPos != cpos) ctx.CodeComplete.ResolveFunction(sci, cpos, autoHide); + if (calltipMember is null) return false; argumentType = ResolveParameterType(paramIndex, true); if (argumentType.IsVoid()) return false; } // complete declaration - MemberModel cMember = ASContext.Context.CurrentMember; - int line = Sci.LineFromPosition(position); - if (cMember == null && !ASContext.Context.CurrentClass.IsVoid()) + var cMember = ctx.CurrentMember; + if (cMember is null && !ctx.CurrentClass.IsVoid()) { - if (!string.IsNullOrEmpty(expr.Value)) - return HandleDeclarationCompletion(Sci, expr.Value, autoHide); - else if (ASContext.Context.CurrentModel.Version >= 2) - return ASGenerator.HandleGeneratorCompletion(Sci, autoHide, features.overrideKey); + if (expr.Value.Length != 0) return HandleDeclarationCompletion(sci, expr.Value, autoHide); + if (ctx.CurrentModel.Version >= 2) return ASGenerator.HandleGeneratorCompletion(sci, autoHide, features.overrideKey); } - else if (cMember != null && line == cMember.LineFrom) + else if (cMember != null && sci.LineFromPosition(position) is { } line && line == cMember.LineFrom) { - string text = Sci.GetLine(line); + var text = sci.GetLine(line); int p; if ((cMember.Flags & FlagType.Constructor) != 0 && !string.IsNullOrEmpty(features.ConstructorKey)) p = text.IndexOfOrdinal(features.ConstructorKey); else p = text.IndexOfOrdinal(cMember.Name); - if (p < 0 || position < Sci.PositionFromLine(line) + p) - return HandleDeclarationCompletion(Sci, expr.Value, autoHide); + if (p < 0 || position < sci.PositionFromLine(line) + p) + return HandleDeclarationCompletion(sci, expr.Value, autoHide); } } - else - { - if (expr.Value.EndsWithOrdinal("..") || Regex.IsMatch(expr.Value, "^[0-9]+\\.")) - return false; - } + else if (expr.Value.EndsWithOrdinal("..") || Regex.IsMatch(expr.Value, "^[0-9]+\\.")) + return false; - string tail = (dotIndex >= 0) ? expr.Value.Substring(dotIndex + features.dot.Length) : expr.Value; - // custom completion - MemberList items = ASContext.Context.ResolveDotContext(Sci, expr, autoHide); + var items = ctx.ResolveDotContext(sci, expr, autoHide); if (items != null) { - DotContextResolved(Sci, expr, items, autoHide); + DotContextResolved(sci, expr, items, autoHide); return true; } + + var tail = (dotIndex >= 0) ? expr.Value.Substring(dotIndex + features.dot.Length) : expr.Value; + + var outOfDate = (expr.Separator == ":") && ctx.UnsetOutOfDate(); + var cClass = ctx.CurrentClass; - // Context ASResult result; - ClassModel tmpClass; - bool outOfDate = (expr.Separator == ":") && ctx.UnsetOutOfDate(); - FileModel cFile = ctx.CurrentModel; - ClassModel cClass = ctx.CurrentClass; - - expr.LocalVars = ParseLocalVars(expr); + ClassModel inClass; if (argumentType != null) { - result = new ASResult(); - tmpClass = argumentType; + inClass = argumentType; expr.LocalVars.Clear(); + result = new ASResult {Context = expr}; } else if (dotIndex > 0) { + expr.LocalVars = ParseLocalVars(expr); // Expression before cursor - result = EvalExpression(expr.Value, expr, cFile, cClass, false, false); + result = EvalExpression(expr.Value, expr, ctx.CurrentModel, cClass, false, false); if (result.IsNull()) { if (outOfDate) ctx.SetOutOfDate(); return true; } - if (autoHide && features.hasE4X && IsXmlType(result.Type)) - return true; - tmpClass = result.Type; + if (autoHide && features.hasE4X && IsXmlType(result.Type)) return true; + inClass = result.Type; } else { - result = new ASResult(); + expr.LocalVars = ParseLocalVars(expr); + result = new ASResult {Context = expr}; if (expr.Separator == "\"") { - tmpClass = ctx.ResolveType(ctx.Features.stringKey, null); - result.Type = tmpClass; + inClass = ResolveType(ctx.Features.stringKey, null); + result.Type = inClass; dotIndex = 1; } - else tmpClass = cClass; + else inClass = cClass; } + var mix = new MemberList(); + ctx.ResolveDotContext(sci, result, mix); - //stores a reference to our current class. tmpClass gets overwritten later, so we need to store the current class separately - ClassModel classScope = tmpClass; - - MemberList mix = new MemberList(); // local vars are the first thing to try - if ((result.IsNull() || (dotIndex < 0)) && expr.ContextFunction != null) - mix.Merge(expr.LocalVars); - - // get all members - FlagType mask = 0; - // members visibility - ClassModel curClass = cClass; - curClass.ResolveExtends(); - Visibility acc = ctx.TypesAffinity(curClass, tmpClass); + if ((result.IsNull() || dotIndex < 0) && expr.ContextFunction != null) mix.Merge(expr.LocalVars); // list package elements if (result.IsPackage) @@ -2099,142 +1977,162 @@ static private bool HandleDotCompletion(ScintillaControl Sci, bool autoHide) // list instance members else if (expr.ContextFunction != null || expr.Separator != ":" || (dotIndex > 0 && !result.IsNull())) { - // user setting may ask to hide some members - bool limitMembers = autoHide; // ASContext.Context.HideIntrinsicMembers || (autoHide && !ASContext.Context.AlwaysShowIntrinsicMembers); - // static or instance members? + FlagType mask; if (!result.IsNull()) mask = result.IsStatic ? FlagType.Static : FlagType.Dynamic; - else if (expr.ContextFunction == null || IsStatic(expr.ContextFunction)) mask = FlagType.Static; + else if (IsStatic(expr.ContextFunction)) mask = FlagType.Static; else mask = 0; if (argumentType != null) mask |= FlagType.Variable; - - // explore members - tmpClass.ResolveExtends(); - if (!limitMembers || result.IsStatic || tmpClass.Name != features.objectKey) - while (tmpClass != null && !tmpClass.IsVoid()) - { - mix.Merge(tmpClass.GetSortedMembersList(), mask, acc); - - // static inheritance - if ((mask & FlagType.Static) > 0) - { - if ((!features.hasStaticInheritance || dotIndex > 0) && (tmpClass.Flags & FlagType.TypeDef) == 0) - break; - } - else if (!features.hasStaticInheritance) mask |= FlagType.Dynamic; - - tmpClass = tmpClass.Extends; - // hide Object class members - if (limitMembers && tmpClass != null && tmpClass.InFile.Package == "" && tmpClass.Name == features.objectKey) - break; - // members visibility - acc = ctx.TypesAffinity(curClass, tmpClass); - } + var limitMembers = autoHide; + if (!limitMembers || result.IsStatic || inClass.Name != features.objectKey) + GetInstanceMembers(autoHide, result, inClass, mask, dotIndex, mix); } - // known classes / toplevel vars/methods - if (argumentType == null && (result.IsNull() || (dotIndex < 0))) + + // known types/toplevel vars/methods + if (argumentType is null && (result.IsNull() || dotIndex < 0)) { - mix.Merge(cFile.GetSortedMembersList()); - mix.Merge(ctx.GetTopLevelElements()); + mix.Merge(ctx.CurrentModel.GetSortedMembersList()); + IEnumerable topLevelElements = ctx.GetTopLevelElements(); + if (expr.ContextFunction != null && expr.ContextFunction.Flags.HasFlag(FlagType.Static)) + topLevelElements = topLevelElements.Where(static it => it.Flags.HasFlag(FlagType.Static)); + mix.Merge(topLevelElements); + if (!ctx.Settings.LazyClasspathExploration && ctx.Settings.CompletionListAllTypes) + mix.Merge(ctx.GetAllProjectClasses()); mix.Merge(ctx.GetVisibleExternalElements()); mix.Merge(GetKeywords()); } // show - List list = new List(); - foreach (MemberModel member in mix) + list ??= new List(mix.Count); + foreach (var member in mix) { - if ((member.Flags & FlagType.Template) > 0) - list.Add(new TemplateItem(member)); - else - list.Add(new MemberItem(member)); + if ((member.Flags & FlagType.Template) > 0) list.Add(new TemplateItem(member)); + else list.Add(new MemberItem(member)); } + if (comparison != null) list.Sort(comparison); EventManager.DispatchEvent(null, new DataEvent(EventType.Command, "ASCompletion.DotCompletion", list)); CompletionList.Show(list, autoHide, tail); // smart focus token - //if (!features.externalCompletion) - AutoselectDotToken(classScope, tail); + AutoselectDotToken(inClass, tail); if (outOfDate) ctx.SetOutOfDate(); return true; } - private static MemberList GetKeywords() + protected virtual void GetInstanceMembers(bool autoHide, ASResult expr, ClassModel exprType, FlagType mask, int dotIndex, MemberList result) + { + var ctx = ASContext.Context; + var features = ctx.Features; + var currentClass = ctx.CurrentClass; + + currentClass.ResolveExtends(); + var access = TypesAffinity(expr.Context, currentClass, exprType); + + // explore members + exprType.ResolveExtends(); + if (exprType.ExtendsType is { } extendsType && !string.IsNullOrEmpty(extendsType) && extendsType != features.objectKey + && exprType.Extends.IsVoid() && !string.IsNullOrEmpty(exprType.Template) && !string.IsNullOrEmpty(exprType.IndexType)) + { + /** + * Temporary fix: + * If `inClass` is generic type with the concrete type explicit definition, like `Null`, + * there can be problems in `inClass.ResolveExtends()` because `inClass` contains a link to the real file with origin declaration, like `Null`, not current file + */ + exprType = exprType.Clone(); + if (expr.InFile != null && !ResolveType(extendsType, expr.InFile).IsVoid()) exprType.InFile = expr.InFile; + else exprType.InFile = ctx.CurrentModel; + exprType.ResolveExtends(); + } + while (!exprType.IsVoid()) + { + result.Merge(exprType.GetSortedMembersList(), mask, access); + // static inheritance + if ((mask & FlagType.Static) > 0) + { + if ((!features.hasStaticInheritance || dotIndex > 0) && (exprType.Flags & FlagType.TypeDef) == 0) + break; + } + else if (!features.hasStaticInheritance) mask |= FlagType.Dynamic; + exprType = exprType.Extends; + // hide Object class members + if (autoHide && !exprType.IsVoid() && exprType.InFile.Package == "" && exprType.Name == features.objectKey) + break; + // members visibility + access = ctx.TypesAffinity(currentClass, exprType); + } + } + + protected virtual Visibility TypesAffinity(ASExpr context, ClassModel inClass, ClassModel withClass) => ASContext.Context.TypesAffinity(inClass, withClass); + + static MemberList GetKeywords() { - IASContext ctx = ASContext.Context; - ContextFeatures features = ctx.Features; - ClassModel cClass = ctx.CurrentClass; - bool inClass = !cClass.IsVoid(); + var ctx = ASContext.Context; + var features = ctx.Features; + var inClass = !ctx.CurrentClass.IsVoid(); - MemberList decl = new MemberList(); + var result = new MemberList(); if (inClass || !ctx.CurrentModel.haXe) { - foreach (string key in features.codeKeywords) - decl.Add(new MemberModel(key, key, FlagType.Template, 0)); + foreach (var key in features.codeKeywords) + result.Add(new MemberModel(key, key, FlagType.Template, 0)); } if (!inClass) { - foreach (string key in features.accessKeywords) - decl.Add(new MemberModel(key, key, FlagType.Template, 0)); - foreach (string key in features.typesKeywords) - decl.Add(new MemberModel(key, key, FlagType.Template, 0)); + foreach (var key in features.accessKeywords) result.Add(new MemberModel(key, key, FlagType.Template, 0)); + foreach (var key in features.typesKeywords) result.Add(new MemberModel(key, key, FlagType.Template, 0)); } - decl.Sort(); - return decl; + result.Sort(); + return result; } - private static bool DeclarationSectionOnly() + static bool DeclarationSectionOnly() { - ClassModel inClass = ASContext.Context.CurrentClass; - if (!inClass.IsVoid() && (inClass.Flags & (FlagType.Enum | FlagType.TypeDef | FlagType.Struct)) > 0) - return true; - return false; + var inClass = ASContext.Context.CurrentClass; + return !inClass.IsVoid() && (inClass.Flags & (FlagType.Enum | FlagType.TypeDef | FlagType.Struct)) > 0; } - private static void AutoselectDotToken(ClassModel classScope, string tail) + static void AutoselectDotToken(ClassModel classScope, string tail) { // remember the latest class resolved for completion to store later the inserted member - currentClassHash = classScope != null ? classScope.QualifiedName : null; + currentClassHash = classScope?.QualifiedName; // if the completion history has a matching entry, it means the user has previously completed from this class. - if (currentClassHash != null && completionHistory.ContainsKey(currentClassHash)) + if (currentClassHash is null) return; + if (!completionHistory.TryGetValue(currentClassHash, out var history)) return; + // If the last-completed member for the class starts with the currently typed text (tail), select it! + // Note that if the tail is currently empty (i.e., the user has just typed the first dot), this still passes. + // This allows it to highlight the last-completed member instantly just by hitting the dot. + // Also does a check if the tail matches exactly the currently selected item; don't change it! + if (CompletionList.SelectedLabel != tail && history.ToLower().StartsWithOrdinal(tail.ToLower())) { - // If the last-completed member for the class starts with the currently typed text (tail), select it! - // Note that if the tail is currently empty (i.e., the user has just typed the first dot), this still passes. - // This allows it to highlight the last-completed member instantly just by hitting the dot. - // Also does a check if the tail matches exactly the currently selected item; don't change it! - if (CompletionList.SelectedLabel != tail && completionHistory[currentClassHash].ToLower().StartsWithOrdinal(tail.ToLower())) - { - CompletionList.SelectItem(completionHistory[currentClassHash]); - } + CompletionList.SelectItem(history); } } - static public void DotContextResolved(ScintillaControl Sci, ASExpr expr, MemberList items, bool autoHide) + public static void DotContextResolved(ScintillaControl sci, ASExpr expr, MemberList items, bool autoHide) { // still valid context and position? - if (Sci != ASContext.CurSciControl) return; - int position = Sci.CurrentPos; - ContextFeatures features = ASContext.Context.Features; - ASExpr local = GetExpression(Sci, position); + if (sci != PluginBase.MainForm.CurrentDocument?.SciControl) return; + var features = ASContext.Context.Features; + var position = sci.CurrentPos; + var local = GetExpression(sci, position); if (!local.Value.StartsWithOrdinal(expr.Value) || expr.Value.LastIndexOfOrdinal(features.dot) != local.Value.LastIndexOfOrdinal(features.dot)) return; - string word = Sci.GetWordLeft(position-1, false); + var word = sci.GetWordLeft(position - 1, false); // current list string reSelect = null; if (CompletionList.Active) reSelect = CompletionList.SelectedLabel; // show completion - List list = new List(); - bool testActive = !CompletionList.Active && expr.Position != position; - foreach (MemberModel member in items) + var list = new List(items.Count); + var testActive = !CompletionList.Active && expr.Position != position; + foreach (var member in items) { - if (testActive && member.Name == word) - return; - list.Add(new MemberItem(member)); + if (testActive && member.Name == word) return; + list.Add(CompletionList.Get(member.Name) ?? new MemberItem(member)); } EventManager.DispatchEvent(null, new DataEvent(EventType.Command, "ASCompletion.DotCompletion", list)); CompletionList.Show(list, autoHide, word); @@ -2246,195 +2144,188 @@ static public void DotContextResolved(ScintillaControl Sci, ASExpr expr, MemberL #region types_completion - static private string SelectTypedNewMember(ScintillaControl sci) + /// + /// List methods to override + /// + /// Don't keep the list open if the word does not match + /// Completion was handled + internal bool HandleOverrideCompletion(string tail, bool autoHide) { - try + var ctx = ASContext.Context; + var curClass = ctx.CurrentClass; + if (curClass.IsVoid()) return false; + + var members = new List(); + curClass.ResolveExtends(); + + const FlagType mask = FlagType.Function | FlagType.Getter | FlagType.Setter; + var tmpClass = curClass.Extends; + var access = ctx.TypesAffinity(curClass, tmpClass); + while (!tmpClass.IsVoid()) { - ASExpr expr = GetExpression(sci, sci.CurrentPos); - if (expr.Value == null) return null; - IASContext ctx = ASContext.Context; - // try local var - expr.LocalVars = ParseLocalVars(expr); - foreach (MemberModel localVar in expr.LocalVars) + if (tmpClass.QualifiedName.StartsWithOrdinal("flash.utils.Proxy")) { - if (localVar.LineTo == ctx.CurrentLine) - { - return localVar.Type; + foreach (var member in tmpClass.Members) + { + member.Namespace = "flash_proxy"; + members.Add(member); } + break; } - // try member - string currentLine = sci.GetLine(sci.CurrentLine); - Match mVarNew = Regex.Match(currentLine, "\\s*(?[a-z_$][a-z._$0-9]*)(?[: ]*)(?[a-z.0-9<>]*)\\s*=\\s*new\\s", RegexOptions.IgnoreCase); - if (mVarNew.Success) + foreach (var member in tmpClass.Members) { - string name = mVarNew.Groups["name"].Value; - ASResult result = EvalExpression(name, expr, ctx.CurrentModel, ctx.CurrentClass, true, false); - if (result != null && result.Member != null && result.Member.Type != null) // Might be missing or wrongly typed member + if (curClass.Members.Contains(member.Name, FlagType.Override, 0)) continue; + if ((member.Flags & FlagType.Dynamic) == 0 + || (member.Access & access) == 0 + || ((member.Flags & FlagType.Function) == 0 && (member.Flags & mask) == 0)) continue; + if (!member.Parameters.IsNullOrEmpty()) { - return result.Member.Type; + foreach (var it in member.Parameters) + { + if ((it.Flags & FlagType.Function) == 0 || it.Parameters is null) continue; + it.Type = ctx.CodeComplete.ToFunctionDeclarationString(it); + it.Parameters = null; + } + // for example: function get value():Function/*(v:*):ReturnType*/ + if ((member.Flags & FlagType.Getter) != 0) + { + member.Type = ctx.CodeComplete.ToFunctionDeclarationString(member); + member.Parameters = null; + } } + members.Add(member); } + tmpClass = tmpClass.Extends; + // members visibility + access = ctx.TypesAffinity(curClass, tmpClass); + } + members.Sort(); + var list = new List(members.Count); + MemberModel last = null; + foreach (var member in members) + { + if (last is null || last.Name != member.Name) + list.Add(new MemberItem(member)); + last = member; } - catch {} // Do not throw exception with incorrect types + if (list.Count > 0) CompletionList.Show(list, autoHide, tail); + return true; + } - return null; + protected static bool HandleNewCompletion(ScintillaControl sci, string tail, bool autoHide, string keyword) + { + List list; + + if (!ASContext.Context.Settings.LazyClasspathExploration + && ASContext.Context.Settings.CompletionListAllTypes) + { + list = GetAllClasses(sci, true, true); + if (list is null) return true; + } + else + { + // Consolidate known classes + var known = GetVisibleElements(); + list = known + .Select(static it => new MemberItem(new MemberModel(it.Type, it.Type, it.Flags, it.Access))) + .ToList(); + } + return ASContext.Context.CodeComplete.HandleNewCompletion(sci, tail, autoHide, keyword, list); } - static private bool HandleNewCompletion(ScintillaControl sci, string tail, bool autoHide, string keyword) + protected virtual bool HandleNewCompletion(ScintillaControl sci, string tail, bool autoHide, string keyword, List list) { - List list; - - if (!ASContext.Context.Settings.LazyClasspathExploration - && ASContext.Context.Settings.CompletionListAllTypes) - { - // show all project classes - list = GetAllClasses(sci, true, true); - - if (list == null) return true; - } - else - { - // Consolidate known classes - MemberList known = GetVisibleElements(); - list = new List(); - foreach (MemberModel member in known) - list.Add(new MemberItem(new MemberModel(member.Type, member.Type, member.Flags, member.Access))); - } - - // If we are instantiating a class: - // 1. Type exists: - // a. Generic type -> Show it with our index type. - // b. Not generic type -> Show existing one - // 2. Type doesn't exist -> Show it with a warning symbol. - string newItemType; - if (keyword == "new" && (newItemType = SelectTypedNewMember(sci)) != null) - { - IASContext ctx = ASContext.Context; - ClassModel aClass = ctx.ResolveType(newItemType, ctx.CurrentModel); - - ICompletionListItem newItem; - if (!aClass.IsVoid()) - { - // AS2 special srictly typed Arrays supports - int p = newItemType.IndexOf('@'); - if (p > -1) + // If we are instantiating a class: + // 1. Type exists: + // a. Generic type -> Show it with our index type. + // b. Not generic type -> Show existing one + // 2. Type doesn't exist -> Show it with a warning symbol. + if (keyword == "new" && !tail.IsNullOrEmpty()) + { + var newItemType = tail; + ICompletionListItem newItem = null; + var aClass = ResolveType(newItemType, ASContext.Context.CurrentModel); + if (!aClass.IsVoid()) + { + // AS2 special srictly typed Arrays supports + if (newItemType.Contains('@', out var p)) newItemType = newItemType.Substring(0, p); + else if (!string.IsNullOrEmpty(aClass.IndexType)) { - newItemType = newItemType.Substring(0, p); - newItem = null; + newItem = new MemberItem(new MemberModel(newItemType, aClass.Type, aClass.Flags, aClass.Access)); } - else if (!string.IsNullOrEmpty(aClass.IndexType)) - { - newItemType = aClass.QualifiedName; - newItem = new MemberItem(new MemberModel(newItemType, aClass.Type, aClass.Flags, aClass.Access)); - } - else - { - newItem = null; - } - } - else if (newItemType == "Vector.") - { - // HACK: Vector.<*> is wrongly parsed! should be looked into. Remove once it's fixed. - newItemType = "Vector"; - newItem = null; - } - else - { - newItem = new NonexistentMemberItem(newItemType); - } - + } + else newItem = new NonexistentMemberItem(newItemType); if (newItem != null) { - int itemIndex = list.FindIndex(item => string.Compare(item.Label, newItem.Label, StringComparison.OrdinalIgnoreCase) >= 0); - - int genericStart = newItemType.IndexOfOrdinal("<"); - if (genericStart > -1 && ASContext.Context.Features.HasGenericsShortNotation) + var itemIndex = list.FindIndex(item => string.Compare(item.Label, newItem.Label, StringComparison.OrdinalIgnoreCase) >= 0); + if (newItemType.Contains('<', out var genericStart) && ASContext.Context.Features.HasGenericsShortNotation) { - newItemType = newItemType.Substring(0, genericStart); - itemIndex = itemIndex > 0 ? itemIndex : 0; - } - else itemIndex = itemIndex > 0 ? itemIndex - 1 : 0; - - list.Insert(itemIndex, newItem); - } - - CompletionList.Show(list, autoHide, tail); - CompletionList.SelectItem(newItemType); - } - else - { - CompletionList.Show(list, autoHide, tail); - } - - return true; + newItemType = newItemType.Substring(0, genericStart); + itemIndex = itemIndex > 0 ? itemIndex : 0; + } + else itemIndex = itemIndex > 0 ? itemIndex - 1 : 0; + list.Insert(itemIndex, newItem); + } + CompletionList.Show(list, autoHide); + CompletionList.SelectItem(newItemType); + } + else CompletionList.Show(list, autoHide, tail); + return true; } - static private bool HandleImportCompletion(ScintillaControl Sci, string tail, bool autoHide) + static bool HandleImportCompletion(ScintillaControl sci, string tail, bool autoHide) { if (!ASContext.Context.Features.hasImports) return false; - if (!ASContext.Context.Settings.LazyClasspathExploration && ASContext.Context.Settings.CompletionListAllTypes) { // show all project classes - HandleAllClassesCompletion(Sci, "", false, false); + HandleAllClassesCompletion(sci, "", false, false); } else { // list visible classes - MemberList known = GetVisibleElements(); - - // show - List list = new List(); - foreach (MemberModel member in known) - list.Add(new MemberItem(member)); + var known = GetVisibleElements(); + var list = known.Select(static it => new MemberItem(it)).ToArray(); CompletionList.Show(list, autoHide, tail); } return true; } - static private bool HandleColonCompletion(ScintillaControl Sci, string tail, bool autoHide) + static bool HandleColonCompletion(ScintillaControl sci, string tail, bool autoHide) { - ComaExpression coma; - if (DeclarationSectionOnly()) coma = ComaExpression.FunctionDeclaration; - else coma = GetFunctionContext(Sci, autoHide); - + var coma = DeclarationSectionOnly() + ? ComaExpression.FunctionDeclaration + : GetFunctionContext(sci, autoHide); if (coma != ComaExpression.FunctionDeclaration && coma != ComaExpression.VarDeclaration) return false; - if (!ASContext.Context.Settings.LazyClasspathExploration - && ASContext.Context.Settings.CompletionListAllTypes) + var ctx = ASContext.Context; + if (!ctx.Settings.LazyClasspathExploration && ctx.Settings.CompletionListAllTypes) { // show all project classes - HandleAllClassesCompletion(Sci, tail, true, false); + HandleAllClassesCompletion(sci, tail, true, false); } else { - bool outOfDate = ASContext.Context.UnsetOutOfDate(); - + var outOfDate = ctx.UnsetOutOfDate(); // list visible classes - MemberList known = GetVisibleElements(); - - // show - List list = new List(); - foreach (MemberModel member in known) - list.Add(new MemberItem(member)); + var known = GetVisibleElements(); + var list = known.Select(static it => new MemberItem(it)).ToArray(); CompletionList.Show(list, autoHide, tail); - if (outOfDate) ASContext.Context.SetOutOfDate(); + if (outOfDate) ctx.SetOutOfDate(); } return true; } - private static ComaExpression GetFunctionContext(ScintillaControl Sci, bool autoHide) + static ComaExpression GetFunctionContext(ScintillaControl sci, bool autoHide) { - ContextFeatures features = ASContext.Context.Features; - ComaExpression coma = ComaExpression.None; - int position = Sci.CurrentPos - 1; - char c = ' '; + var position = sci.CurrentPos - 1; + var c = ' '; //bool inGenericType = false; while (position > 0) { - c = (char)Sci.CharAt(position); + c = (char)sci.CharAt(position); //if (c == '<') inGenericType = true; if (c == ':' || c == ';' || c == '=' || c == ',') break; position--; @@ -2442,18 +2333,20 @@ private static ComaExpression GetFunctionContext(ScintillaControl Sci, bool auto position--; // var declaration - GetWordLeft(Sci, ref position); - string keyword = (c == ':') ? GetWordLeft(Sci, ref position) : null; + GetWordLeft(sci, ref position); + var ctx = ASContext.Context; + var features = ctx.Features; + var keyword = c == ':' ? GetWordLeft(sci, ref position) : null; if (keyword == features.varKey || (features.constKey != null && keyword == features.constKey)) - coma = ComaExpression.VarDeclaration; + return ComaExpression.VarDeclaration; // function return type - else if ((char)Sci.CharAt(position) == ')') + if ((char)sci.CharAt(position) == ')') { - int parCount = 0; + var parCount = 0; while (position > 0) { position--; - c = (char)Sci.CharAt(position); + c = (char)sci.CharAt(position); if (c == ')') parCount++; else if (c == '(') { @@ -2465,121 +2358,175 @@ private static ComaExpression GetFunctionContext(ScintillaControl Sci, bool auto } } } - keyword = GetWordLeft(Sci, ref position); - if (keyword == "" && Sci.CharAt(position) == '>' && features.hasGenerics) + keyword = GetWordLeft(sci, ref position); + if (keyword.Length == 0 && sci.CharAt(position) == '>' && features.hasGenerics) { - int groupCount = 1; + var groupCount = 1; position--; while (position >= 0 && groupCount > 0) { - c = (char)Sci.CharAt(position); - if ("({[<".IndexOf(c) > -1) - groupCount--; - else if (")}]>".IndexOf(c) > -1) - groupCount++; + c = (char)sci.CharAt(position); + if ("({[<".Contains(c)) groupCount--; + else if (")}]>".Contains(c)) groupCount++; position--; } - keyword = GetWordLeft(Sci, ref position); - } - if (keyword == features.functionKey) - coma = ComaExpression.FunctionDeclaration; - else - { - keyword = GetWordLeft(Sci, ref position); - if (keyword == features.functionKey || keyword == features.getKey || keyword == features.setKey) - coma = ComaExpression.FunctionDeclaration; - else if (ASContext.Context.CurrentModel.haXe && keyword == features.varKey && - (ASContext.Context.CurrentMember == null || (ASContext.Context.CurrentMember.Flags & FlagType.Function) == 0)) - coma = ComaExpression.VarDeclaration; // Haxe Properties - } - } - // needs more guessing - else - { - // config constant, or namespace access - if (keyword == "" && position > 0 && (char)Sci.CharAt(position) == ':') - { - int pos = position - 1; - keyword = GetWordLeft(Sci, ref pos); - if (keyword != "" && autoHide) return ComaExpression.None; + keyword = GetWordLeft(sci, ref position); } - coma = DisambiguateComa(Sci, position, 0); - } - return coma; + if (keyword == features.functionKey) return ComaExpression.FunctionDeclaration; + keyword = GetWordLeft(sci, position); + if (keyword == features.functionKey || keyword == features.getKey || keyword == features.setKey) + return ComaExpression.FunctionDeclaration; + if (ctx.CurrentModel.haXe + && keyword == features.varKey + && (ctx.CurrentMember is null || (ctx.CurrentMember.Flags & FlagType.Function) == 0)) + return ComaExpression.VarDeclaration; // Haxe Properties + return ComaExpression.None; + } + // config constant, or namespace access + if (autoHide && string.IsNullOrEmpty(keyword) && position > 0 && (char)sci.CharAt(position) == ':') + { + keyword = GetWordLeft(sci, position - 1); + if (keyword.Length == 0) return ComaExpression.None; + } + return DisambiguateComa(sci, position, 0); } /// /// Display the full project classes list /// - /// - static public void HandleAllClassesCompletion(ScintillaControl Sci, string tail, bool classesOnly, bool showClassVars) + /// + public static void HandleAllClassesCompletion(ScintillaControl sci, string tail, bool classesOnly, bool showClassVars) { - List list = GetAllClasses(Sci, classesOnly, showClassVars); + var list = GetAllClasses(sci, classesOnly, showClassVars); list.Sort(new CompletionItemCaseSensitiveImportComparer()); CompletionList.Show(list, false, tail); } - static private bool HandleInterpolationCompletion(ScintillaControl sci, bool autoHide, bool expressions) + static bool HandleInterpolationCompletion(ScintillaControl sci, bool autoHide, bool expressions) { - IASContext ctx = ASContext.Context; - MemberList members = new MemberList(); - ASExpr expr = GetExpression(sci, sci.CurrentPos); - if (expr.ContextMember == null) return false; - + var expr = GetExpression(sci, sci.CurrentPos); + if (expr.ContextMember is null) return false; + var ctx = ASContext.Context; + var members = new MemberList(); members.Merge(ctx.CurrentClass.GetSortedMembersList()); - if ((expr.ContextMember.Flags & FlagType.Static) > 0) members.RemoveAllWithoutFlag(FlagType.Static); - else - members.Merge(ctx.CurrentClass.GetSortedInheritedMembersList()); - + else members.Merge(ctx.CurrentClass.GetSortedInheritedMembersList()); members.Merge(ParseLocalVars(expr)); - - if (!expressions) - { - members.RemoveAllWithFlag(FlagType.Function); - } - - List list = new List(); - foreach (MemberModel member in members) - list.Add(new MemberItem(member)); + if (!expressions) members.RemoveAllWithFlag(FlagType.Function); + var list = members.Select(static it => new MemberItem(it)).ToArray(); CompletionList.Show(list, autoHide); - return true; } #endregion - private static bool HandleMetadataCompletion(bool autoHide) - { - List list = new List(); - foreach (KeyValuePair meta in ASContext.Context.Features.metadata) - { - MemberModel member = new MemberModel(); - member.Name = meta.Key; - member.Comments = meta.Value; - member.Type = "Compiler Metadata"; - list.Add(new MemberItem(member)); - CompletionList.Show(list, autoHide); - } - return true; - } - - #region expression_evaluator - /// - /// Find expression type in function context + /// Handle completion after inserting a space character /// - /// To evaluate - /// Completion context + /// Scintilla control + /// Current cursor position + /// Don't keep the list open if the word does not match + /// Auto-completion has been handled + bool HandleWhiteSpaceCompletion(ScintillaControl sci, int position, bool autoHide) + { + var pos = position - 1; + var word = GetWordLeft(sci, ref pos); + if (HandleWhiteSpaceCompletion(sci, position, word, autoHide)) return true; + var ctx = ASContext.Context; + var features = ctx.Features; + if (word.Length == 0) + { + var c = (char)sci.CharAt(pos); + if (c == ':' && features.hasEcmaTyping) return HandleColonCompletion(sci, string.Empty, autoHide); + if (c == ',') + { + var currentClass = ctx.CurrentClass; + if (currentClass.Flags.HasFlag(FlagType.Class) && PositionIsBeforeBody(sci, pos, currentClass)) + { + var endPosition = sci.PositionFromLine(currentClass.LineFrom); + for (var i = pos; i > endPosition; i--) + { + if (sci.PositionIsOnComment(i)) continue; + var e = GetExpressionType(sci, i, false, true); + if (e.Type == currentClass) break; + var value = e.Context.Value; + if (value == features.ExtendsKey) break; + if (value == features.ImplementsKey) return HandleNewCompletion(sci, string.Empty, autoHide, string.Empty); + i -= value.Length; + } + } + } + if (autoHide && (c == '(' || c == ',') && !ASContext.CommonSettings.DisableCallTip) + return HandleFunctionCompletion(sci, autoHide); + return false; + } + // import + if (features.hasImports && (word == features.importKey || word == features.importKeyAlt)) + return HandleImportCompletion(sci, string.Empty, autoHide); + if (word == features.PackageKey || features.typesKeywords.Contains(word)) return false; + if (word == features.ImplementsKey) return HandleImplementsCompletion(sci, autoHide); + // new/extends/instanceof/... + if (features.HasTypePreKey(word)) + { + var tail = string.Empty; + // for example: var v:Type = new $(EntryPoint) + if (GetOperatorLeft(sci, ref pos) == "=" && GetExpression(sci, pos)?.Value is { } v) + tail = v; + return HandleNewCompletion(sci, tail, autoHide, word); + } + if (features.OperatorKeywords.Contains(word)) return OnChar(sci, '.', autoHide); + var expr = CurrentResolvedContext?.Result?.Context; + var beforeBody = expr is not null && (expr.ContextFunction is null || expr.BeforeBody); + if (!beforeBody && features.codeKeywords.Contains(word)) return false; + if (word == features.overrideKey) return ASGenerator.HandleGeneratorCompletion(sci, autoHide, word); + // public/internal/private/protected/static + if (features.accessKeywords.Contains(word)) return HandleDeclarationCompletion(sci, string.Empty, autoHide); + return false; + } + + /// + /// Handle completion after inserting a space character + /// + /// Scintilla control + /// Current cursor position + /// Word before cursor + /// Don't keep the list open if the word does not match + /// Auto-completion has been handled + protected virtual bool HandleWhiteSpaceCompletion(ScintillaControl sci, int position, string wordLeft, bool autoHide) => false; + + /// + /// Display the full project interfaces list + /// + /// Scintilla control + /// Don't keep the list open if the word does not match + /// Auto-completion has been handled + protected virtual bool HandleImplementsCompletion(ScintillaControl sci, bool autoHide) + { + var classes = ASContext.Context.GetAllProjectClasses(); + var list = new List(classes.Count); + foreach (var it in classes) + { + if (!it.Flags.HasFlag(FlagType.Interface)) continue; + list.Add(new MemberItem(it)); + } + CompletionList.Show(list, autoHide); + return true; + } + + #region expression_evaluator + + /// + /// Find expression type in function context + /// + /// To evaluate + /// Completion context /// File context /// Class context /// Complete (sub-expression) or partial (dot-completion) evaluation /// /// Class/member struct - private static ASResult EvalExpression(string expression, ASExpr context, FileModel inFile, ClassModel inClass, bool complete, bool asFunction) - { - return EvalExpression(expression, context, inFile, inClass, complete, asFunction, true); - } + static ASResult EvalExpression(string expression, ASExpr context, FileModel inFile, ClassModel inClass, bool complete, bool asFunction) + => ASContext.Context.CodeComplete.EvalExpression(expression, context, inFile, inClass, complete, asFunction, true); /// /// Find expression type in function context @@ -2592,64 +2539,45 @@ private static ASResult EvalExpression(string expression, ASExpr context, FileMo /// /// /// Class/member struct - private static ASResult EvalExpression(string expression, ASExpr context, FileModel inFile, ClassModel inClass, bool complete, bool asFunction, bool filterVisibility) + protected virtual ASResult EvalExpression(string expression, ASExpr context, FileModel inFile, ClassModel inClass, bool complete, bool asFunction, bool filterVisibility) { - ASResult notFound = new ASResult {Context = context}; + var notFound = new ASResult {Context = context}; if (string.IsNullOrEmpty(expression)) return notFound; - var value = expression.TrimEnd('.'); - if (context.SubExpressions?.Count == 1) value = value.Replace(char.IsLetter(value[0]) ? ".#0~" : "#0~", context.SubExpressions.First()); - if (!string.IsNullOrEmpty(context.WordBefore) && ASContext.Context.Features.OtherOperators.Contains(context.WordBefore)) - { - value = context.WordBefore + " " + value; - } - - var ctx = ASContext.Context; - var type = ctx.ResolveToken(value, inClass.InFile); - if (!type.IsVoid()) return new ASResult {Type = type, Context = context, InClass = inClass, InFile = inFile, Path = context.Value}; - - var features = ctx.Features; - if (expression.StartsWithOrdinal(features.dot)) + if (expression[0] == '.') { - if (expression.StartsWithOrdinal(features.dot + "#")) expression = expression.Substring(1); + if (expression.StartsWithOrdinal(".#")) expression = expression.Substring(1); else if (context.Separator == "\"") expression = "\"" + expression; else return notFound; } - string[] tokens = Regex.Split(expression, Regex.Escape(features.dot)); - - // eval first token - string token = tokens[0]; + var tokens = Split(expression); + var token = tokens[0]; if (token.Length == 0) return notFound; if (asFunction && tokens.Length == 1) token += "("; - type = ctx.ResolveToken(token, inClass.InFile); - if (!type.IsVoid()) return EvalTail(context, inFile, new ASResult {Type = type}, tokens, complete, filterVisibility) ?? notFound; - ASResult head = null; + var ctx = ASContext.Context; + var features = ctx.Features; + ASResult head; if (token[0] == '#') { - Match mSub = re_sub.Match(token); + var mSub = re_sub.Match(token); if (mSub.Success) { - string subExpr = context.SubExpressions[Convert.ToInt16(mSub.Groups["index"].Value)]; + var subExpr = context.SubExpressions[Convert.ToInt16(mSub.Groups["index"].Value)]; // parse sub expression subExpr = subExpr.Substring(1, subExpr.Length - 2).Trim(); - ASExpr subContext = new ASExpr(context); + var subContext = new ASExpr(context); subContext.SubExpressions = ExtractedSubex = new List(); subExpr = re_balancedParenthesis.Replace(subExpr, ExtractSubex); - Match m = re_refineExpression.Match(subExpr); + var m = re_refineExpression.Match(subExpr); if (!m.Success) return notFound; - Regex re_dot = new Regex("[\\s]*" + Regex.Escape(features.dot) + "[\\s]*"); + var re_dot = new Regex("[\\s]*" + Regex.Escape(features.dot) + "[\\s]*"); subExpr = re_dot.Replace(re_whiteSpace.Replace(m.Value, " "), features.dot).Trim(); - int space = subExpr.LastIndexOf(' '); - if (space > 0) - { - string trash = subExpr.Substring(0, space).TrimEnd(); - subExpr = subExpr.Substring(space + 1); - if (trash.EndsWithOrdinal("as")) subExpr += features.dot + "#"; - } + var space = subExpr.LastIndexOf(' '); + if (space > 0) subExpr = subExpr.Substring(space + 1); // eval sub expression head = EvalExpression(subExpr, subContext, inFile, inClass, true, false); if (head.Member != null) - head.Type = ctx.ResolveType(head.Member.Type, head.Type.InFile); + head.Type = ResolveType(head.Member.Type, head.Type.InFile); } else { @@ -2657,8 +2585,14 @@ private static ASResult EvalExpression(string expression, ASExpr context, FileMo head = EvalVariable(token, context, inFile, inClass); } } - else if (token.Contains("<")) head = new ASResult {Type = ctx.ResolveType(token, inFile)}; - else head = EvalVariable(token, context, inFile, inClass); // regular eval + else + { + var type = ctx.ResolveToken(token, inClass.InFile); + if (!type.IsVoid()) return EvalTail(context, inFile, new ASResult {Type = type}, tokens, complete, filterVisibility) ?? notFound; + head = token.Contains('<') + ? new ASResult {Type = ResolveType(token, inFile)} + : EvalVariable(token, context, inFile, inClass); + } // no head, exit if (head.IsNull()) return notFound; @@ -2671,51 +2605,66 @@ private static ASResult EvalExpression(string expression, ASExpr context, FileMo return notFound; // resolve - ASResult result = EvalTail(context, inFile, head, tokens, complete, filterVisibility); + var result = EvalTail(context, inFile, head, tokens, complete, filterVisibility); // if failed, try as qualified class name - if ((result == null || result.IsNull()) && tokens.Length > 1) + if ((result is null || result.IsNull()) && tokens.Length > 1) { - ClassModel qualif = ctx.ResolveType(expression, null); - if (!qualif.IsVoid()) + var qualif = ResolveType(expression, null); + if (!qualif.IsVoid()) return new ASResult {Context = context, IsStatic = true, InFile = qualif.InFile, Type = qualif}; + } + return result ?? notFound; + // Utils + static string[] Split(string expr) + { + var list = new List(); + var groupCount = 0; + var prevStartIndex = 0; + var length = expr.Length - 1; + for (var i = 0; i <= length; i++) { - result = new ASResult(); - result.Context = context; - result.IsStatic = true; - result.InFile = qualif.InFile; - result.Type = qualif; + var c = expr[i]; + if (c == '[' || c == '(' || c == '{') groupCount++; + else if (c == ']' || c == ')' || c == '}') groupCount--; + if (groupCount == 0 && (c == '.' || i == length)) + { + var len = i - prevStartIndex; + if (c != '.' && i == length) len++; + list.Add(expr.Substring(prevStartIndex, len)); + prevStartIndex = i + 1; + if (c == '.' && i == length) list.Add(string.Empty); + } } + if (list.Count == 0) list.Add(expr); + return list.ToArray(); } - return result ?? notFound; } - static ASResult EvalTail(ASExpr context, FileModel inFile, ASResult head, string[] tokens, bool complete, bool filterVisibility) + static ASResult EvalTail(ASExpr context, FileModel inFile, ASResult head, IList tokens, bool complete, bool filterVisibility) { // eval tail - int n = tokens.Length; + int n = tokens.Count; if (!complete) n--; // context - ContextFeatures features = ASContext.Context.Features; - ASResult step = head; - ClassModel resultClass = head.Type; + var ctx = ASContext.Context; + var features = ctx.Features; + var step = head; // look for static or dynamic members? - FlagType mask = head.IsStatic ? FlagType.Static : FlagType.Dynamic; + var mask = head.IsStatic ? FlagType.Static : FlagType.Dynamic; // members visibility - IASContext ctx = ASContext.Context; - ClassModel curClass = ctx.CurrentClass; + var curClass = ctx.CurrentClass; curClass.ResolveExtends(); - Visibility acc = ctx.TypesAffinity(curClass, step.Type); + var acc = ctx.CodeComplete.TypesAffinity(context, curClass, step.Type); // explore - bool inE4X = false; - string token = tokens[0]; - string path = token; - step.Path = token; + var inE4X = false; + var path = tokens[0]; + step.Path = path; step.Context = context; - for (int i=1; i 0) { - if ((mask & FlagType.Static) > 0) - { - mask -= FlagType.Static; - mask |= FlagType.Dynamic; - } + mask -= FlagType.Static; + mask |= FlagType.Dynamic; } } else @@ -2816,10 +2761,7 @@ static ASResult EvalTail(ASExpr context, FileModel inFile, ASResult head, string return step; } - private static bool IsStatic(MemberModel member) - { - return member != null && (member.Flags & FlagType.Static) > 0; - } + static bool IsStatic(MemberModel member) => member != null && (member.Flags & FlagType.Static) > 0; /// /// Find variable type in function context @@ -2829,235 +2771,280 @@ private static bool IsStatic(MemberModel member) /// File context /// Class context /// Class/member struct - private static ASResult EvalVariable(string token, ASExpr local, FileModel inFile, ClassModel inClass) + static ASResult EvalVariable(string token, ASExpr local, FileModel inFile, ClassModel inClass) { - ASResult result = new ASResult(); + var result = new ASResult(); if (local.coma == ComaExpression.AnonymousObjectParam) return result; - IASContext context = ASContext.Context; + var ctx = ASContext.Context; if (!inClass.IsVoid()) inFile = inClass.InFile; - int p = token.IndexOf('('); + var p = token.IndexOf('('); if (p > 0) token = token.Substring(0, p); // top-level elements resolution - context.ResolveTopLevelElement(token, result); + ctx.ResolveTopLevelElement(token, result); if (!result.IsNull()) { if (result.Member != null && (result.Member.Flags & FlagType.Function) > 0 && p < 0) result.Type = ResolveType("Function", null); return result; } - if (!inClass.IsVoid() && !string.IsNullOrEmpty(context.Features.ConstructorKey) && token == context.Features.ConstructorKey && local.BeforeBody) + var features = ctx.Features; + if (!inClass.IsVoid() && !string.IsNullOrEmpty(features.ConstructorKey) && token == features.ConstructorKey && local.BeforeBody) return EvalVariable(inClass.Name, local, inFile, inClass); - var contextMember = local.ContextMember; - if (contextMember == null || local.coma != ComaExpression.None || !local.BeforeBody || (contextMember.Flags & (FlagType.Getter | FlagType.Setter)) > 0) + if (local.Separator != ":") { - // local vars - if (local.LocalVars != null) + var contextMember = local.ContextMember; + if (contextMember is null + || (contextMember.Flags & (FlagType.Getter | FlagType.Setter)) > 0 + || local.coma != ComaExpression.None + || local.WordBefore != features.functionKey) { - // Haxe 3 get/set keyword in properties declaration - if ((token == "set" || token == "get") && local.ContextFunction == null - && contextMember != null && contextMember.Parameters != null && contextMember.Parameters.Count == 2) - { - if (token == "get" && contextMember.Parameters[0].Name == "get") return EvalVariable("get_" + contextMember.Name, local, inFile, inClass); - if (token == "set" && contextMember.Parameters[1].Name == "set") return EvalVariable("set_" + contextMember.Name, local, inFile, inClass); - } - - var subExpressionsCount = local.SubExpressions?.Count ?? 0; - foreach (MemberModel var in local.LocalVars) + // local vars + if (local.LocalVars != null) { - if (var.Name == token && (subExpressionsCount == 0 || var.Flags.HasFlag(FlagType.Function))) + // Haxe 3 get/set keyword in properties declaration + if ((token == "set" || token == "get") && local.ContextFunction is null && contextMember?.Parameters != null && contextMember.Parameters.Count == 2) { - result.Member = var; - result.InFile = inFile; - result.InClass = inClass; - if (var.Type == null && var.Flags.HasFlag(FlagType.LocalVar) && context.Features.hasInference) - InferVariableType(local, var); - - if (var.Flags.HasFlag(FlagType.Function)) - result.Type = context.ResolveType("Function", null); - else - result.Type = ResolveType(var.Type, inFile); - - return result; + if (token == "get" && contextMember.Parameters[0].Name == "get") return EvalVariable("get_" + contextMember.Name, local, inFile, inClass); + if (token == "set" && contextMember.Parameters[1].Name == "set") return EvalVariable("set_" + contextMember.Name, local, inFile, inClass); } - } - } - // method parameters - if (local.ContextFunction != null && local.ContextFunction.Parameters != null) - { - foreach (MemberModel para in local.ContextFunction.Parameters) - if (para.Name == token || (para.Name[0] == '?' && para.Name.Substring(1) == token)) + if (local.LocalVars.Count > 0) { - result.Member = para; - result.Type = ResolveType(para.Type, inFile); - return result; + var vars = local.LocalVars.Where(it => it.Name == token).ToList(); + if (vars.Count > 0) + { + MemberModel var = null; + if (vars.Count > 1) + { + vars.Sort((l, r) => r.LineFrom.CompareTo(l.LineFrom)); + var = vars.FirstOrDefault(it => it.LineTo < local.LineTo); + } + var ??= vars.FirstOrDefault(); + if (var != null) + { + result.Member = var; + result.InFile = inFile; + result.InClass = inClass; + if (features.hasInference && (var.Type is null || ResolveType(var.Type, inFile).IsVoid())) + { + if (var.Flags.HasFlag(FlagType.Variable)) ctx.CodeComplete.InferType(PluginBase.MainForm.CurrentDocument?.SciControl, local, var); + } + if (string.IsNullOrEmpty(var.Type)) result.Type = ResolveType(features.objectKey, null); + else if (var.Flags.HasFlag(FlagType.Function)) result.Type = ResolveType("Function", null); + else result.Type = ResolveType(var.Type, inFile); + return result; + } + } } + } + // method parameters + if (local.ContextFunction?.Parameters != null) + { + foreach (var para in local.ContextFunction.Parameters) + if (para.Name == token || (para.Name[0] == '?' && para.Name.Substring(1) == token)) + { + result.Member = para; + result.Type = ResolveType(para.Type, inFile); + return result; + } + } } } + // class members if (!inClass.IsVoid()) { FindMember(token, inClass, result, 0, 0); if (!result.IsNull()) + { + if (features.hasInference && result.Member is {Type: null} member) + { + ctx.CodeComplete.InferType(PluginBase.MainForm.CurrentDocument?.SciControl, local, member); + if (member.Type != null) result.Type = ResolveType(member.Type, inFile); + } return result; + } } // file member if (inFile.Version != 2 || inClass.IsVoid()) { FindMember(token, inFile, result, 0, 0); - if (!result.IsNull()) - return result; + if (!result.IsNull()) return result; } // current file types - foreach(ClassModel aClass in inFile.Classes) + foreach(var aClass in inFile.Classes) { - if (aClass.Name == token) - { - if (!context.InPrivateSection || aClass.Access == Visibility.Private) - { - result.Type = aClass; - result.IsStatic = (p < 0); - return result; - } - } + if (aClass.Name != token || (ctx.InPrivateSection && aClass.Access != Visibility.Private)) continue; + result.Type = aClass; + result.IsStatic = p < 0; + return result; } // visible types & declarations - var visible = context.GetVisibleExternalElements(); - foreach (MemberModel aDecl in visible) + var list = ctx.GetVisibleExternalElements(); + foreach (var aDecl in list) { - if (aDecl.Name == token) + if (aDecl.Name != token) continue; + if ((aDecl.Flags & FlagType.Package) > 0) { - if ((aDecl.Flags & FlagType.Package) > 0) - { - FileModel package = context.ResolvePackage(token, false); - if (package != null) - { - result.InFile = package; - result.IsPackage = true; - result.IsStatic = true; - return result; - } - } - else if ((aDecl.Flags & (FlagType.Class | FlagType.Enum)) > 0) + var package = ctx.ResolvePackage(token, false); + if (package != null) { - ClassModel friendClass = null; - if (aDecl.InFile != null) - { - foreach(ClassModel aClass in aDecl.InFile.Classes) - if (aClass.Name == token) - { - friendClass = aClass; - break; - } - } - if (friendClass == null) friendClass = context.ResolveType(aDecl.Type, inFile); - - if (!friendClass.IsVoid()) - { - result.Type = friendClass; - result.IsStatic = (p < 0); - return result; - } + result.InFile = package; + result.IsPackage = true; + result.IsStatic = true; + return result; } - else if ((aDecl.Flags & FlagType.Function) > 0) + } + else if ((aDecl.Flags & (FlagType.Class | FlagType.Enum)) > 0) + { + ClassModel friendClass = null; + if (aDecl.InFile != null) { - result.Member = aDecl; - result.RelClass = ClassModel.VoidClass; - result.InClass = FindClassOf(aDecl); - result.Type = (p < 0) - ? context.ResolveType("Function", null) - : context.ResolveType(aDecl.Type, aDecl.InFile); - result.InFile = aDecl.InFile; - return result; + foreach(var aClass in aDecl.InFile.Classes) + if (aClass.Name == token) + { + friendClass = aClass; + break; + } } - else if ((aDecl.Flags & (FlagType.Variable | FlagType.Getter)) > 0) + friendClass ??= ResolveType(aDecl.Type, inFile); + if (!friendClass.IsVoid()) { - result.Member = aDecl; - result.RelClass = ClassModel.VoidClass; - result.InClass = FindClassOf(aDecl); - result.Type = context.ResolveType(aDecl.Type, aDecl.InFile); - result.InFile = aDecl.InFile; + result.Type = friendClass; + result.IsStatic = p < 0; return result; } } + else if ((aDecl.Flags & FlagType.Function) > 0) + { + result.Member = aDecl; + result.RelClass = ClassModel.VoidClass; + result.InClass = FindClassOf(aDecl); + result.Type = (p < 0) + ? ResolveType("Function", null) + : ResolveType(aDecl.Type, aDecl.InFile); + result.InFile = aDecl.InFile; + return result; + } + else if ((aDecl.Flags & (FlagType.Variable | FlagType.Getter)) > 0) + { + result.Member = aDecl; + result.RelClass = ClassModel.VoidClass; + result.InClass = FindClassOf(aDecl); + result.Type = ResolveType(aDecl.Type, aDecl.InFile); + result.InFile = aDecl.InFile; + return result; + } } return result; } - private static ClassModel FindClassOf(MemberModel aDecl) + static ClassModel FindClassOf(MemberModel aDecl) { - if (aDecl.InFile != null) - foreach (ClassModel aClass in aDecl.InFile.Classes) + if (aDecl.InFile is null) return ClassModel.VoidClass; + foreach (var aClass in aDecl.InFile.Classes) + { + if (aClass.Members.Any(member => member == aDecl)) { - foreach (MemberModel member in aClass.Members) - if (member == aDecl) return aClass; + return aClass; } + } return ClassModel.VoidClass; } - private static ClassModel ResolveType(string qname, FileModel inFile) + /// + /// Retrieves a class model from its name + /// + /// Class (short or full) name + /// Current file + /// A parsed class or an empty ClassModel if the class is not found + protected static ClassModel ResolveType(string cname, FileModel inFile) { - if (qname == null) return ClassModel.VoidClass; - IASContext context = ASContext.Context; - bool isQualified = qname.IndexOf('.') > 0; - - if (inFile == null || inFile == context.CurrentModel) - foreach (MemberModel aDecl in context.GetVisibleExternalElements()) + if (cname is null) return ClassModel.VoidClass; + var ctx = ASContext.Context; + if (inFile is null || inFile == ctx.CurrentModel) + { + var isQualified = cname.Contains('.'); + foreach (var aDecl in ctx.GetVisibleExternalElements()) { - if (aDecl.Name == qname || (isQualified && aDecl.Type == qname)) + if (aDecl.Name == cname || (isQualified && aDecl.Type == cname)) { - if (aDecl.InFile != null) - { - foreach (ClassModel aClass in aDecl.InFile.Classes) - if (aClass.Name == aDecl.Name) return aClass; - return context.GetModel(aDecl.InFile.Package, qname, inFile != null ? inFile.Package : null); - } - else return context.ResolveType(aDecl.Type, inFile); + if (aDecl.InFile is null) return ctx.ResolveType(aDecl.Type, inFile); + return aDecl.InFile.Classes.FirstOrDefault(it => it.Name == aDecl.Name) + ?? ctx.GetModel(aDecl.InFile.Package, cname, inFile?.Package); } } - - return context.ResolveType(qname, inFile); + } + return ctx.ResolveType(cname, inFile); } - /// - /// Infer very simple cases: var foo = {expression} - /// - private static void InferVariableType(ASExpr local, MemberModel var) + public void InferType(ScintillaControl sci, MemberModel member) => InferType(sci, new ASExpr(), member); + + protected virtual void InferType(ScintillaControl sci, ASExpr local, MemberModel member) { - ScintillaControl sci = ASContext.CurSciControl; - if (sci == null || var.LineFrom >= sci.LineCount) - return; - // is it a simple affectation inference? - string text = sci.GetLine(var.LineFrom); - Regex reVar = new Regex("\\s*var\\s+" + var.Name + "\\s*=([^;]+)"); - Match m = reVar.Match(text); - if (m.Success && m.Groups[1].Length > 1) - { - int p = text.IndexOf(';'); - text = text.TrimEnd(); - if (p < 0) p = text.Length; - if (text.EndsWith('(')) p--; - // resolve expression - ASExpr expr = GetExpression(sci, sci.PositionFromLine(var.LineFrom) + p, true); - if (!string.IsNullOrEmpty(expr.Value)) - { - ASResult result = EvalExpression(expr.Value, expr, ASContext.Context.CurrentModel, ASContext.Context.CurrentClass, true, false); - if (!result.IsNull()) - { - if (result.Type != null && !result.Type.IsVoid()) - { - var.Type = result.Type.QualifiedName; - var.Flags |= FlagType.Inferred; - } - else if (result.Member != null) - { - var.Type = result.Member.Type; - var.Flags |= FlagType.Inferred; - } - } + var lineStartPosition = sci.PositionFromLine(member.LineFrom); + var lineEndPosition = sci.LineEndPosition(member.LineFrom); + for (var i = lineStartPosition; i < lineEndPosition; i++) + { + if (sci.PositionIsOnComment(i) || sci.PositionIsInString(i)) continue; + var c = (char) sci.CharAt(i); + if (c == '=' || c == ';') break; + if (c == '_' || c == ',' || c == '(' || c == ')') continue; + if (char.IsPunctuation(c)) return; + } + var text = sci.GetLine(member.LineFrom); + var m = Regex.Match(text, "=([^;]+)"); + if (!m.Success) return; + var rvalue = m.Groups[1]; + if (rvalue.Length == 0) return; + var offset = rvalue.Length - rvalue.Value.TrimStart().Length; + var rvalueStart = lineStartPosition + rvalue.Index + offset; + if (local.ContextFunction is {} function) + { + /** + * for example: + * function foo() { + * var expr = foo(); + * return expr; + * } + */ + var p = rvalueStart; + if (function.Name == GetWordRight(sci, ref p) && GetCharRight(sci, ref p) == '(') + { + // TODO slavara: trace possible stack overflow error + member.Type = function.Type ?? ASContext.Context.Features.voidKey; + member.Flags |= FlagType.Inferred; + return; } } + InferVariableType(sci, text, rvalueStart, local, member); + } + + protected virtual void InferVariableType(ScintillaControl sci, string declarationLine, int rvalueStart, ASExpr local, MemberModel var) + { + if (!var.Flags.HasFlag(FlagType.Variable) && !var.Flags.HasFlag(FlagType.ParameterVar)) return; + var p = declarationLine.IndexOf(';'); + var text = declarationLine.TrimEnd(); + if (p < 0) p = text.Length; + if (text.EndsWith('(')) p--; + // resolve expression + var expr = GetExpression(sci, sci.PositionFromLine(var.LineFrom) + p, true); + if (string.IsNullOrEmpty(expr.Value)) return; + var ctx = ASContext.Context; + var result = EvalExpression(expr.Value, expr, ctx.CurrentModel, ctx.CurrentClass, true, false); + if (result.IsNull()) return; + if (result.Type != null && !result.Type.IsVoid()) + { + var.Type = result.Type.QualifiedName; + var.Flags |= FlagType.Inferred; + } + else if (result.Member != null) + { + var.Type = result.Member.Type; + if (string.IsNullOrEmpty(var.Type)) var.Type = ResolveType(ctx.Features.objectKey, null).Name; + var.Flags |= FlagType.Inferred; + } } /// @@ -3067,17 +3054,19 @@ private static void InferVariableType(ASExpr local, MemberModel var) /// In given file /// Class/Member struct /// Flags mask - /// Visibility mask - public static void FindMember(string token, FileModel inFile, ASResult result, FlagType mask, Visibility acc) + /// Visibility mask + public static void FindMember(string token, FileModel inFile, ASResult result, FlagType mask, Visibility access) + => ASContext.Context.CodeComplete.FindMemberEx(token, inFile, result, mask, access); + + protected virtual void FindMemberEx(string token, FileModel inFile, ASResult result, FlagType mask, Visibility access) { - if (string.IsNullOrEmpty(token)) - return; + if (string.IsNullOrEmpty(token)) return; // package if (result.IsPackage) { - string fullName = (result.InFile.Package.Length > 0) ? result.InFile.Package + "." + token : token; - int p; + var ctx = ASContext.Context; + var fullName = (result.InFile.Package.Length > 0) ? result.InFile.Package + "." + token : token; foreach (MemberModel mPack in result.InFile.Imports) { if (mPack.Name == token) @@ -3085,7 +3074,7 @@ public static void FindMember(string token, FileModel inFile, ASResult result, F // sub-package if (mPack.Flags == FlagType.Package) { - FileModel package = ASContext.Context.ResolvePackage(fullName, false); + var package = ctx.ResolvePackage(fullName, false); if (package != null) result.InFile = package; else { @@ -3097,24 +3086,24 @@ public static void FindMember(string token, FileModel inFile, ASResult result, F else { result.IsPackage = false; - result.Type = ResolveType(fullName, ASContext.Context.CurrentModel); + result.Type = ResolveType(fullName, ctx.CurrentModel); result.InFile = result.Type.InFile; } return; } - else if ((p = mPack.Name.IndexOf('<')) > 0) + if (mPack.Name.Contains('<', out var p) && p > 0) { if (p > 1 && mPack.Name[p - 1] == '.') p--; if (mPack.Name.Substring(0, p) == token) { result.IsPackage = false; - result.Type = ResolveType(fullName + mPack.Name.Substring(p), ASContext.Context.CurrentModel); + result.Type = ResolveType(fullName + mPack.Name.Substring(p), ctx.CurrentModel); result.InFile = result.Type.InFile; return; } } } - foreach (MemberModel member in result.InFile.Members) + foreach (var member in result.InFile.Members) { if (member.Name == token) { @@ -3134,15 +3123,14 @@ public static void FindMember(string token, FileModel inFile, ASResult result, F return; } - MemberModel found; // variable - found = inFile.Members.Search(token, mask, acc); + var found = inFile.Members.Search(token, mask, access); // ignore setters if (found != null && (found.Flags & FlagType.Setter) > 0) { found = null; - MemberList matches = inFile.Members.MultipleSearch(token, mask, acc); - foreach (MemberModel member in matches) + var matches = inFile.Members.MultipleSearch(token, mask, access); + foreach (var member in matches) { found = member; if ((member.Flags & FlagType.Setter) == 0) break; @@ -3155,7 +3143,6 @@ public static void FindMember(string token, FileModel inFile, ASResult result, F result.Member = found; result.Type = ResolveType(found.Type, inFile); result.IsStatic = false; - return; } } @@ -3166,174 +3153,176 @@ public static void FindMember(string token, FileModel inFile, ASResult result, F /// In given class /// Class/Member struct /// Flags mask - /// Visibility mask - public static void FindMember(string token, ClassModel inClass, ASResult result, FlagType mask, Visibility acc) - { - if (string.IsNullOrEmpty(token)) - return; - - IASContext context = ASContext.Context; - ContextFeatures features = context.Features; - MemberModel found = null; - ClassModel tmpClass = inClass; + /// Visibility mask + public static void FindMember(string token, ClassModel inClass, ASResult result, FlagType mask, Visibility access) + => ASContext.Context.CodeComplete.FindMemberEx(token, inClass, result, mask, access); - if (inClass == null) + protected virtual void FindMemberEx(string token, ClassModel inClass, ASResult result, FlagType mask, Visibility access) + { + if (string.IsNullOrEmpty(token)) return; + if (inClass is null) { - if (result.InFile != null) FindMember(token, result.InFile, result, mask, acc); + if (result.InFile != null) FindMember(token, result.InFile, result, mask, access); return; } - else result.RelClass = inClass; + var features = ASContext.Context.Features; + result.RelClass = inClass; // previous member accessed as an array - if (token.Length >= 2 && token.First() == '[' && token.Last() == ']') + if (token.Length >= 2 && token[0] == '[' && token[token.Length - 1] == ']') { result.IsStatic = false; - if (result.Type == null || result.Type.IndexType == null) + if (result.Type?.IndexType is null) { result.Member = null; result.InFile = null; - result.Type = ResolveType(context.Features.objectKey, null); - } - else - { - result.Type = ResolveType(result.Type.IndexType, result.InFile); + result.Type = ResolveType(features.objectKey, null); } + else result.Type = ResolveType(result.Type.IndexType, result.InFile); return; } // previous member called as a method - else if (token[0] == '#') + if (token[0] == '#') { result.IsStatic = false; if (result.Member != null) { - if ((result.Member.Flags & FlagType.Constructor) > 0) - result.Type = inClass; - else result.Type = ResolveType(result.Member.Type, result.InFile); + result.Type = (result.Member.Flags & FlagType.Constructor) > 0 + ? inClass + : ResolveType(result.Member.Type, result.InFile); } return; } // variable - else if (tmpClass != null) + MemberModel found = null; + // member + var tmpClass = inClass; + tmpClass.ResolveExtends(); + while (!tmpClass.IsVoid()) { - // member - tmpClass.ResolveExtends(); - while (!tmpClass.IsVoid()) + found = tmpClass.Members.Search(token, mask, access); + // ignore setters + if (found != null && (found.Flags & FlagType.Setter) > 0) { - found = tmpClass.Members.Search(token, mask, acc); - // ignore setters - if (found != null && (found.Flags & FlagType.Setter) > 0) + found = null; + var matches = tmpClass.Members.MultipleSearch(token, mask, access); + foreach (var member in matches) { - found = null; - MemberList matches = tmpClass.Members.MultipleSearch(token, mask, acc); - foreach (MemberModel member in matches) - { - found = member; - if ((member.Flags & FlagType.Getter) > 0) break; - } + found = member; + if ((member.Flags & FlagType.Getter) > 0) break; } - if (found != null) + } + if (found != null) + { + result.Member = found; + // variable / getter + if ((found.Flags & FlagType.Function) == 0) { - result.Member = found; - // variable / getter - if ((found.Flags & FlagType.Function) == 0) - { - result.Type = ResolveType(found.Type, tmpClass.InFile); - result.IsStatic = false; - } - // constructor - else if ((found.Flags & FlagType.Constructor) > 0) - { - // is the constructor - ie. a Type - if (tmpClass != inClass) // constructor of inherited type - { - found = null; - result.Type = null; - result.Member = null; - break; - } - result.Type = tmpClass; - result.IsStatic = true; - } - // in enum - else if ((found.Flags & FlagType.Enum) > 0) - { - result.Type = ResolveType(found.Type, tmpClass.InFile); - } - // method - else - { - result.Type = ResolveType("Function", null); - result.IsStatic = false; - } - break; + result.Type = ResolveType(found.Type, tmpClass.InFile); + result.IsStatic = false; } - // Flash IDE-like typing - else if (tmpClass.Name == "MovieClip") + // constructor + else if ((found.Flags & FlagType.Constructor) > 0) { - string autoType = null; - if (tmpClass.InFile.Version < 3) - { - if (token.EndsWithOrdinal("_mc") || token.StartsWithOrdinal("mc")) autoType = "MovieClip"; - else if (token.EndsWithOrdinal("_txt") || token.StartsWithOrdinal("txt")) autoType = "TextField"; - else if (token.EndsWithOrdinal("_btn") || token.StartsWithOrdinal("bt")) autoType = "Button"; - } - else if (tmpClass.InFile.Version == 3) - { - if (token.EndsWithOrdinal("_mc") || token.StartsWithOrdinal("mc")) autoType = "flash.display.MovieClip"; - else if (token.EndsWithOrdinal("_txt") || token.StartsWithOrdinal("txt")) autoType = "flash.text.TextField"; - else if (token.EndsWithOrdinal("_btn") || token.StartsWithOrdinal("bt")) autoType = "flash.display.SimpleButton"; - } - if (autoType != null) + // is the constructor - ie. a Type + if (tmpClass != inClass) // constructor of inherited type { - result.Type = ASContext.Context.ResolveType(autoType, null); - result.Member = new MemberModel(token, autoType, FlagType.Variable | FlagType.Dynamic | FlagType.AutomaticVar, Visibility.Public); - result.IsStatic = false; - return; + found = null; + result.Type = null; + result.Member = null; + break; } + result.Type = tmpClass; + result.IsStatic = true; } - - // static inheritance: only AS2 and Haxe typedefs inherit static members - if ((mask & FlagType.Static) > 0) + // in enum + else if ((found.Flags & FlagType.Enum) > 0) { - if (!features.hasStaticInheritance && (tmpClass.Flags & FlagType.TypeDef) == 0) - break; + result.Type = ResolveType(found.Type, tmpClass.InFile); } - - tmpClass = tmpClass.Extends; - - if (acc == 0 && !tmpClass.IsVoid() && tmpClass.InFile.Version == 3) + // method + else + { + result.Type = ResolveType("Function", null); + result.IsStatic = false; + } + break; + } + // Flash IDE-like typing + if (tmpClass.Name == "MovieClip") + { + string autoType = null; + if (tmpClass.InFile.Version < 3) + { + if (token.EndsWithOrdinal("_mc") || token.StartsWithOrdinal("mc")) autoType = "MovieClip"; + else if (token.EndsWithOrdinal("_txt") || token.StartsWithOrdinal("txt")) autoType = "TextField"; + else if (token.EndsWithOrdinal("_btn") || token.StartsWithOrdinal("bt")) autoType = "Button"; + } + else if (tmpClass.InFile.Version == 3) + { + if (token.EndsWithOrdinal("_mc") || token.StartsWithOrdinal("mc")) + autoType = "flash.display.MovieClip"; + else if (token.EndsWithOrdinal("_txt") || token.StartsWithOrdinal("txt")) + autoType = "flash.text.TextField"; + else if (token.EndsWithOrdinal("_btn") || token.StartsWithOrdinal("bt")) + autoType = "flash.display.SimpleButton"; + } + if (autoType != null) { - acc = Visibility.Public | Visibility.Protected; - if (inClass.InFile.Package == tmpClass.InFile.Package) acc |= Visibility.Internal; + result.Type = ResolveType(autoType, null); + result.Member = new MemberModel(token, autoType, FlagType.Variable | FlagType.Dynamic | FlagType.AutomaticVar, Visibility.Public); + result.IsStatic = false; + return; } } + // static inheritance: only AS2 and Haxe typedefs inherit static members + if ((mask & FlagType.Static) > 0) + { + if (!features.hasStaticInheritance && (tmpClass.Flags & FlagType.TypeDef) == 0) + break; + } + tmpClass = tmpClass.Extends; + if (access == 0 && !tmpClass.IsVoid() && tmpClass.InFile.Version == 3) + { + access = Visibility.Public | Visibility.Protected; + if (inClass.InFile.Package == tmpClass.InFile.Package) access |= Visibility.Internal; + } } - // result found! if (found != null) { result.InClass = tmpClass; result.InFile = tmpClass.InFile; - if (result.Type == null) - result.Type = ASContext.Context.ResolveType(found.Type, tmpClass.InFile); + result.Type ??= ResolveType(found.Type, tmpClass.InFile); return; } // try subpackages - else if (inClass.InFile.TryAsPackage) + if (inClass.InFile.TryAsPackage) { - result.Type = ASContext.Context.ResolveType(inClass.Name + "." + token, null); - if (!result.Type.IsVoid()) - return; + result.Type = ResolveType(inClass.Name + "." + token, null); + if (!result.Type.IsVoid()) return; } - // not found result.Type = null; result.Member = null; } + public static MemberModel FindMember(string name, ClassModel inClass) + { + var list = inClass == ClassModel.VoidClass + ? ASContext.Context.CurrentModel.Members + : inClass.Members; + + return list.FirstOrDefault(member => member.Name == name); + } + + public static T FindMember(int line, IEnumerable list) where T : MemberModel + => list.FirstOrDefault(it => it.LineFrom <= line && it.LineTo >= line); + #endregion #region main_code_parser - private static List ExtractedSubex; + + static List ExtractedSubex; /// /// Find expression at cursor position @@ -3350,94 +3339,119 @@ public static void FindMember(string token, ClassModel inClass, ASResult result, /// Cursor position /// Skip whitespace at position /// - private static ASExpr GetExpression(ScintillaControl sci, int position, bool ignoreWhiteSpace) + protected static ASExpr GetExpression(ScintillaControl sci, int position, bool ignoreWhiteSpace) + => ASContext.Context.CodeComplete.GetExpressionEx(sci, position, ignoreWhiteSpace); + + /// + /// Find expression at cursor position + /// + /// Scintilla Control + /// Cursor position + /// Skip whitespace at position + /// + protected virtual ASExpr GetExpressionEx(ScintillaControl sci, int position, bool ignoreWhiteSpace) { - bool haXe = ASContext.Context.CurrentModel.haXe; - ASExpr expression = new ASExpr(); - expression.Position = position; - expression.Separator = " "; + var ctx = ASContext.Context; + var haXe = ctx.CurrentModel.haXe; + var expression = new ASExpr {Position = position, Separator = " "}; + var minPos = 0; // file's member declared at this position - expression.ContextMember = ASContext.Context.CurrentMember; - int minPos = 0; - if (expression.ContextMember != null) + MemberModel contextMember = null; + var currentLine = sci.LineFromPosition(position); + if (sci.FileName != ctx.CurrentFile) { - minPos = sci.PositionFromLine(expression.ContextMember.LineFrom); - StringBuilder sbBody = new StringBuilder(); - for (int i = expression.ContextMember.LineFrom; i <= expression.ContextMember.LineTo; i++) - sbBody.Append(sci.GetLine(i)); - var body = sbBody.ToString(); - + var model = ctx.GetFileModel(sci.FileName); + if (FindMember(currentLine, model.Classes) is { } contextClass) + contextMember = FindMember(currentLine, contextClass.Members); + contextMember ??= FindMember(currentLine, model.Members); + } + else contextMember = FindMember(currentLine, ctx.CurrentClass.Members); + if (contextMember != null) + { + expression.ContextMember = contextMember; + minPos = sci.PositionFromLine(contextMember.LineFrom); + var body = sci.GetTextRange(minPos, sci.PositionFromLine(contextMember.LineTo + 1)); var hasBody = FlagType.Function | FlagType.Constructor; if (!haXe) hasBody |= FlagType.Getter | FlagType.Setter; - - if ((expression.ContextMember.Flags & hasBody) > 0) + if (!contextMember.Flags.HasFlag(FlagType.Variable) && (contextMember.Flags & hasBody) > 0) { - expression.ContextFunction = expression.ContextMember; - expression.FunctionOffset = expression.ContextMember.LineFrom; - - Match mStart = Regex.Match(body, "(\\)|[a-z0-9*.,-<>])\\s*{", RegexOptions.IgnoreCase); - if (mStart.Success) + expression.ContextFunction = contextMember; + expression.FunctionOffset = contextMember.LineFrom; + var m = Regex.Match(body, "(\\)|[a-z0-9*.,-<>])\\s*{", RegexOptions.IgnoreCase); + if (m.Success) { // cleanup function body & offset - int pos = mStart.Index + mStart.Length - 1; - expression.BeforeBody = (position < sci.PositionFromLine(expression.ContextMember.LineFrom) + pos); - string pre = body.Substring(0, pos); - for (int i = 0; i < pre.Length - 1; i++) - if (pre[i] == '\r') { expression.FunctionOffset++; if (pre[i + 1] == '\n') i++; } + var pos = m.Index + m.Length - 1; + expression.BeforeBody = (position < minPos + pos); + var pre = body.Substring(0, pos); + for (var i = 0; i < pre.Length - 1; i++) + if (pre[i] == '\r') + { + expression.FunctionOffset++; + if (pre[i + 1] == '\n') i++; + } else if (pre[i] == '\n') expression.FunctionOffset++; + body = body.Substring(pos); } expression.FunctionBody = body; } else { - int eqPos = body.IndexOf('='); - expression.BeforeBody = (eqPos < 0 || position < sci.PositionFromLine(expression.ContextMember.LineFrom) + eqPos); + var eqPos = body.IndexOf('='); + expression.BeforeBody = (eqPos < 0 || position < minPos + eqPos); } } // get the word characters from the syntax definition - string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; + var characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; // get expression before cursor - ContextFeatures features = ASContext.Context.Features; - StringBuilder sb = new StringBuilder(); - StringBuilder sbSub = new StringBuilder(); - int subCount = 0; - char c = ' '; + var features = ctx.Features; + var sb = new StringBuilder(); + var sbSub = new StringBuilder(); + var subCount = 0; + var c = ' '; var startPosition = position; - int positionExpression = position; - int arrCount = 0; - int parCount = 0; - int genCount = 0; + var positionExpression = position; + var arrCount = 0; + var parCount = 0; + var genCount = 0; var braCount = 0; var dQuotes = 0; var sQuotes = 0; - bool hasGenerics = features.hasGenerics; - bool hadWS = false; - bool hadDot = ignoreWhiteSpace; - int dotCount = 0; - bool inRegex = false; - char dot = features.dot[features.dot.Length - 1]; + var hasGenerics = features.hasGenerics; + var hadWS = false; + var hadDot = ignoreWhiteSpace; + var dotCount = 0; + var inRegex = false; + var dot = features.dot[features.dot.Length - 1]; while (position > minPos) { position--; - var style = sci.BaseStyleAt(position); - if (style == 14) // regex literal + if (arrCount == 0 && braCount == 0 && parCount == 0 && ctx.CodeComplete.IsRegexStyle(sci, position)) { - if (hadDot) inRegex = true; - else break; + inRegex = true; + positionExpression = position; + continue; } - else if (!IsCommentStyle(style)) + var style = sci.BaseStyleAt(position); + if (!IsCommentStyle(style)) { // end of regex literal if (inRegex) { - inRegex = false; - if (expression.SubExpressions == null) expression.SubExpressions = new List(); + if (expression.SubExpressions is null) + { + expression.SubExpressions = new List(); + expression.SubExpressionPositions = new List(); + } expression.SubExpressions.Add(""); - sb.Insert(0, "RegExp.#" + (subCount++) + "~"); + expression.SubExpressionPositions.Add(position + 1); + sb.Insert(0, "#RegExp.#" + (subCount++) + "~"); + expression.Separator = ";"; + break; } var c2 = c; c = (char)sci.CharAt(position); @@ -3446,124 +3460,199 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign sbSub.Insert(0, c); continue; } + if (arrCount == 0 && braCount == 0 && parCount == 0 + && dQuotes == 0 && sQuotes == 0 + && c != '\"' && c != '\'' + && (IsStringStyle(style) || IsCharStyle(style)) + && !IsStringInterpolationStyle(sci, position)) break; // array access - if (c == ']') arrCount++; - else if (c == '[') + if (c == ']') { - arrCount--; - if (arrCount == 0 && braCount == 0) + if (parCount == 0) { - if (sbSub.Length > 0) sbSub.Insert(0, '['); - if (parCount == 0) + /** + * for example: + * var v = [] + * v. + */ + if (!hadDot && sb.Length > 0 && characterClass.Contains(sb[0])) + { + expression.Separator = ";"; + break; + } + ignoreWhiteSpace = false; + if (arrCount == 0) // start sub-expression { - sb.Insert(0, "." + sbSub); + if (expression.SubExpressions is null) + { + expression.SubExpressions = new List(); + expression.SubExpressionPositions = new List(); + } sbSub.Clear(); } - continue; - } - if (arrCount < 0) - { - expression.Separator = ";"; - break; + arrCount++; } } - else if (c == '<' && hasGenerics && arrCount == 0) + else if (c == '[') { - genCount--; - if (genCount < 0) + if (parCount == 0) { - expression.Separator = ";"; - break; + arrCount--; + if (arrCount == 0 && braCount == 0) + { + positionExpression = position; + sbSub.Insert(0, c); + expression.SubExpressions.Add(sbSub.ToString()); + expression.SubExpressionPositions.Add(position + 1); + sbSub.Clear(); + sb.Insert(0, ".#" + (subCount++) + "~"); + var pos = position - 1; + var word = GetWordLeft(sci, ref pos); + // for example: return []. + if (word.Length > 0 && features.codeKeywords.Contains(word)) + { + expression.Separator = ";"; + expression.WordBefore = word; + expression.WordBeforePosition = pos + 1; + break; + } + continue; + } + if (arrCount < 0) + { + expression.Separator = ";"; + break; + } } } - // ignore sub-expressions (method calls' parameters) - else if (c == '(') + else if (c == '<') { - parCount--; - if (parCount == 0 && arrCount == 0) + if (hasGenerics && arrCount == 0 && parCount == 0) { - sbSub.Insert(0, c); - int testPos = position - 1; - string testWord = GetWordLeft(sci, ref testPos); - expression.SubExpressions.Add(sbSub.ToString()); - sbSub.Clear(); - sb.Insert(0, ".#" + (subCount++) + "~"); // method call or sub expression - if (testWord == "return" || testWord == "case" || testWord == "default") + genCount--; + if (genCount < 0) { - // AS3, AS2, Loom ex: return (a as B). expression.Separator = ";"; - expression.WordBefore = testWord; - expression.WordBeforePosition = testPos + 1; break; } - continue; } - if (parCount < 0) + } + else if (c == '>') + { + if (arrCount == 0 && parCount == 0) { - expression.Separator = ";"; - int testPos = position - 1; - string testWord = GetWordLeft(sci, ref testPos); // anonymous function - var pos = testPos; - string testWord2 = GetWordLeft(sci, ref pos) ?? "null"; // regular function - if (testWord == features.functionKey || testWord == "catch" - || testWord2 == features.functionKey - || testWord2 == features.getKey || testWord2 == features.setKey) + // for example: -> + if (haXe && position - 1 > minPos && (char)sci.CharAt(position - 1) == '-') { - expression.Separator = ","; - expression.coma = ComaExpression.FunctionDeclaration; } - else + else if (hasGenerics) { - expression.WordBefore = testWord; - expression.WordBeforePosition = testPos + 1; + if (c2 == '.' || c2 == ',' || c2 == '(' || c2 == '[' || c2 == '>' || c2 == '}' || c2 == ')' || position + 1 == startPosition) + { + genCount++; + var length = sb.Length; + if (length >= 3) + { + var fc = sb[0]; + var sc = sb[1]; + var lc = sb[length - 1]; + if (fc == '.' && sc == '[' && (lc == ']' || (length >= 4 && sb[length - 2] == ']' && lc == '.'))) + { + sbSub.Insert(0, sb.ToString(1, length - 1)); + sb.Clear(); + } + } + } + else break; } - break; } } - else if (c == ')') + // ignore sub-expressions (method calls' parameters) + else if (c == '(') { - if (!hadDot) - { - expression.Separator = ";"; - break; - } - if (parCount == 0) // start sub-expression + if (arrCount == 0) { - if (expression.SubExpressions == null) expression.SubExpressions = new List(); - sbSub = new StringBuilder(); + parCount--; + if (parCount == 0) + { + positionExpression = position; + sbSub.Insert(0, c); + expression.SubExpressions.Add(sbSub.ToString()); + expression.SubExpressionPositions.Add(position + 1); + sbSub.Clear(); + sb.Insert(0, ".#" + (subCount++) + "~"); // method call or sub expression + var pos = position - 1; + var word = GetWordLeft(sci, ref pos); + // AS3, AS2, Loom ex: return (a as B). + if (word.Length > 0 && word != "new" && word != "trace" && features.codeKeywords.Contains(word)) + { + expression.Separator = ";"; + expression.WordBefore = word; + expression.WordBeforePosition = pos + 1; + break; + } + continue; + } + if (parCount < 0) + { + expression.Separator = ";"; + var testPos = position - 1; + var testWord = GetWordLeft(sci, ref testPos); // anonymous function + var testWord2 = GetWordLeft(sci, testPos); // regular function + if (testWord == features.functionKey + || testWord == "catch" + || testWord2 == features.functionKey + || testWord2 == features.getKey + || testWord2 == features.setKey) + { + expression.Separator = ","; + expression.coma = ComaExpression.FunctionDeclaration; + } + else + { + expression.WordBefore = testWord; + expression.WordBeforePosition = testPos + 1; + } + break; + } } - parCount++; } - else if (c == '>' && arrCount == 0) + else if (c == ')') { - if (haXe && position - 1 > minPos && (char) sci.CharAt(position - 1) == '-') - { - } - else if (hasGenerics) + if (arrCount == 0) { - if (c2 == '.' || c2 == ',' || c2 == '(' || c2 == '[' || c2 == '>' || c2 == '}' || c2 == ')' || position + 1 == startPosition) + ignoreWhiteSpace = false; + if (!hadDot) + { + expression.Separator = ";"; + break; + } + if (parCount == 0) // start sub-expression { - genCount++; - var length = sb.Length; - if (length >= 3) + if (expression.SubExpressions is null) { - var fc = sb[0]; - var sc = sb[1]; - var lc = sb[length - 1]; - if (fc == '.' && sc == '[' && (lc == ']' || (length >= 4 && sb[length - 2] == ']' && lc == '.'))) - { - sbSub.Insert(0, sb.ToString(1, length - 1)); - sb.Clear(); - } + expression.SubExpressions = new List(); + expression.SubExpressionPositions = new List(); } + sbSub.Clear(); } - else break; + parCount++; } } else if (genCount == 0 && arrCount == 0 && parCount == 0) { if (c == '}') { + /** + * for example: + * var v = {} + * v. + */ + if (!hadDot && sb.Length > 0 && characterClass.Contains(sb[0])) + { + expression.Separator = ";"; + break; + } if (!ignoreWhiteSpace && hadWS) { expression.Separator = ";"; @@ -3576,6 +3665,7 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign braCount--; if (braCount == 0) { + positionExpression = position; sb.Insert(0, "{}"); expression.Separator = ";"; continue; @@ -3597,26 +3687,32 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign dQuotes--; if (dQuotes == 0) { + positionExpression = position; expression.Separator = ";"; if (expression.SubExpressions != null) { - sbSub.Insert(0, "\""); + sbSub.Insert(0, c); sb.Insert(0, sbSub.ToString()); break; } - sb.Insert(0, "\"" + sbSub + "\""); - positionExpression = position; + sb.Insert(0, string.Concat(c, sbSub, c)); continue; } } if (hadDot) { sbSub.Clear(); - sbSub.Insert(0, "\""); - if (expression.SubExpressions == null) expression.SubExpressions = new List(); + sbSub.Insert(0, c); + if (expression.SubExpressions is null) + { + expression.SubExpressions = new List(); + expression.SubExpressionPositions = new List(); + } expression.SubExpressions.Add(string.Empty); + expression.SubExpressionPositions.Add(position + 1); sb.Insert(0, ".#" + (subCount++) + "~"); } + ignoreWhiteSpace = false; continue; } if (c == '\'' && dQuotes == 0) @@ -3628,56 +3724,57 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign sQuotes--; if (sQuotes == 0) { + positionExpression = position; expression.Separator = ";"; if (expression.SubExpressions != null) { - sbSub.Insert(0, "'"); + sbSub.Insert(0, c); sb.Insert(0, sbSub.ToString()); break; } - sb.Insert(0, "'" + sbSub + "'"); - positionExpression = position; + sb.Insert(0, string.Concat(c, sbSub, c)); continue; } } if (hadDot) { sbSub.Clear(); - sbSub.Insert(0, "'"); - if (expression.SubExpressions == null) expression.SubExpressions = new List(); + sbSub.Insert(0, c); + if (expression.SubExpressions is null) + { + expression.SubExpressions = new List(); + expression.SubExpressionPositions = new List(); + } expression.SubExpressions.Add(string.Empty); + expression.SubExpressionPositions.Add(position + 1); sb.Insert(0, ".#" + (subCount++) + "~"); } + ignoreWhiteSpace = false; continue; } } } - if (parCount > 0 || arrCount > 0 || genCount > 0 || braCount > 0 || dQuotes > 0 || sQuotes > 0) + if (parCount > 0 || arrCount > 0 || genCount > 0 || braCount > 0) { - if (c == ';') // not expected: something's wrong - { - expression.Separator = ";"; - break; - } // build sub expression sbSub.Insert(0, c); continue; } // build expression - if (c <= 32) + if (c <= ' ') { if (genCount == 0) hadWS = true; else { sb.Insert(sb.Length, sbSub.ToString().ToCharArray()); + positionExpression = position + 1; expression.Separator = " "; break; } } else if (c == dot) { - if (features.dot.Length == 2) - hadDot = position > 0 && sci.CharAt(position - 1) == features.dot[0]; + if (features.dot.Length == 2) hadDot = position > 0 && sci.CharAt(position - 1) == features.dot[0]; else { hadDot = true; @@ -3689,41 +3786,26 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign } sb.Insert(0, c); } - else if (characterClass.IndexOf(c) >= 0) - { - if (hadWS && !hadDot) - { - expression.Separator = " "; - break; - } - hadWS = false; - hadDot = false; - dotCount = 0; - sb.Insert(0, c); - positionExpression = position; - } else if (c == ';') { if(expression.Separator == " ") expression.Separator = ";"; break; } - else if (hasGenerics && c == '<') + else if (c == '<' && hasGenerics) { sbSub.Insert(0, c); if (genCount < 0 && sci.ConfigurationLanguage == "as3" && position > minPos && sci.CharAt(position - 1) != '.') { + positionExpression = position; position--; expression.Separator = " "; break; } - if (subCount > 0) - { - sb.Insert(0, sbSub); - sbSub.Clear(); - } genCount--; + sb.Insert(0, sbSub); + sbSub.Clear(); } else if (c == '{') { @@ -3735,9 +3817,7 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign sb.Append(c); braCount++; position++; - int endPos; - if (expression.ContextFunction != null) endPos = sci.LineEndPosition(expression.ContextFunction.LineTo); - else endPos = sci.LineEndPosition(expression.ContextMember.LineTo); + var endPos = sci.LineEndPosition(expression.ContextFunction?.LineTo ?? expression.ContextMember.LineTo); while (position < endPos) { style = sci.BaseStyleAt(position); @@ -3759,23 +3839,26 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign else if (c == ',') { expression.coma = DisambiguateComa(sci, position, minPos); - expression.Separator = (expression.coma == ComaExpression.None) ? ";" : ","; + expression.Separator = ","; + expression.SeparatorPosition = position; break; } else if (c == ':') { expression.Separator = ":"; - break; - } - else if (c == '=') - { - expression.Separator = "="; + expression.SeparatorPosition = position; break; } else if (features.ArithmeticOperators.Contains(c)) { - expression.SeparatorPosition = position; var p = position - 1; + // for example: 5e-324, 1.79e+308 + if ((c == '-' || c == '+') && p > minPos && sci.CharAt(p) == 'e') + { + sb.Insert(0, c); + continue; + } + expression.SeparatorPosition = position; var curOp = c.ToString(); foreach (var op in features.IncrementDecrementOperators) { @@ -3823,6 +3906,19 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign expression.RightOperator = curOp; hadDot = true; } + else if (characterClass.Contains(c)) + { + if (hadWS && !hadDot) + { + expression.Separator = " "; + break; + } + hadWS = false; + hadDot = false; + dotCount = 0; + sb.Insert(0, c); + positionExpression = position; + } else //if (hadWS && !hadDot) { if (hadDot && features.SpecialPostfixOperators.Contains(c)) @@ -3831,7 +3927,6 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign continue; } if (c == '\'' || c == '"') expression.Separator = "\""; - else expression.Separator = ";"; break; } } @@ -3845,23 +3940,30 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign } } } - - // check if there is a particular keyword - if (expression.Separator == " ") - { - expression.WordBefore = GetWordLeft(sci, ref position); - expression.WordBeforePosition = position + 1; - } - + var value = sb.ToString().TrimStart('.'); if (features.hasE4X && value.Length >= 2 && value[0] == '<' && value[value.Length - 1] == '>') { expression.Separator = ";"; value = ""; } - + expression.Value = value; expression.PositionExpression = positionExpression; + expression.LineFrom = sci.LineFromPosition(positionExpression); + expression.LineTo = sci.LineFromPosition(expression.Position); + // check if there is a particular keyword + if (expression.Separator == " " && position > 0) + { + var pos = position; + expression.WordBefore = GetWordLeft(sci, ref pos); + if (expression.WordBefore.Length > 0) + { + position = pos; + expression.WordBeforePosition = position + 1; + } + } + GetOperatorLeft(sci, position, expression); LastExpression = expression; return expression; } @@ -3872,7 +3974,7 @@ private static ASExpr GetExpression(ScintillaControl sci, int position, bool ign /// internal static ComaExpression DisambiguateComa(ScintillaControl sci, int position, int minPos) { - ContextFeatures features = ASContext.Context.Features; + var features = ASContext.Context.Features; // find block start '(' or '{' int parCount = 0; int braceCount = 0; @@ -3880,58 +3982,45 @@ internal static ComaExpression DisambiguateComa(ScintillaControl sci, int positi while (position > minPos) { var c = (char)sci.CharAt(position); - if (c == ';') - { - return ComaExpression.None; - } - // var declaration - else if (c == ':') + if (c == ';') return ComaExpression.None; + if (c == ':') { position--; - string word = GetWordLeft(sci, ref position); - word = GetWordLeft(sci, ref position); + GetWordLeft(sci, ref position); + var word = GetWordLeft(sci, ref position); if (word == features.varKey) return ComaExpression.VarDeclaration; - else continue; + continue; } // Array values - else if (c == '[') + if (c == '[') { sqCount--; - if (sqCount < 0) - { - return ComaExpression.ArrayValue; - } - } - else if (c == ']') - { - sqCount++; + if (sqCount < 0) return ComaExpression.ArrayValue; } - // function declaration or parameter + else if (c == ']') sqCount++; else if (c == '(') { parCount--; if (parCount < 0) { position--; - string word1 = GetWordLeft(sci, ref position); - if (word1 == "" && sci.CharAt(position) == '>' && features.hasGenerics) + var word1 = GetWordLeft(sci, ref position); + if (word1.Length == 0 && sci.CharAt(position) == '>' && features.hasGenerics) { // Generic function: function generic(arg:K) int groupCount = 1; position--; while (position >= 0 && groupCount > 0) { - c = (char)sci.CharAt(position); - if ("({[<".IndexOf(c) > -1) - groupCount--; - else if (")}]>".IndexOf(c) > -1) - groupCount++; + c = (char) sci.CharAt(position); + if ("({[<".Contains(c)) groupCount--; + else if (")}]>".Contains(c)) groupCount++; position--; } word1 = GetWordLeft(sci, ref position); } if (word1 == features.functionKey) return ComaExpression.FunctionDeclaration; // anonymous function - string word2 = GetWordLeft(sci, ref position); + var word2 = GetWordLeft(sci, ref position); if (word2 == features.functionKey || word2 == features.setKey || word2 == features.getKey) return ComaExpression.FunctionDeclaration; // function declaration if (features.hasDelegates && word2 == "delegate") @@ -3939,28 +4028,24 @@ internal static ComaExpression DisambiguateComa(ScintillaControl sci, int positi return ComaExpression.FunctionParameter; // function call } } - else if (c == ')') - { - parCount++; - } - // code block or anonymous object + else if (c == ')') parCount++; else if (c == '{') { braceCount--; if (braceCount < 0) { position--; - string word1 = GetWordLeft(sci, ref position); - c = (word1.Length > 0) ? word1[word1.Length - 1] : (char)sci.CharAt(position); - if (":,(=".IndexOf(c) >= 0) + var word1 = GetWordLeft(sci, ref position); + c = word1.Length > 0 ? word1[word1.Length - 1] : (char) sci.CharAt(position); + if (":,(=".Contains(c)) { - string line = sci.GetLine(sci.LineFromPosition(position)); + var line = sci.GetLine(sci.LineFromPosition(position)); //TODO: Very limited check, the case|default could be in a previous line, or it could be something else in the same line if (Regex.IsMatch(line, @"\b(case|default)\b.*:")) break; // case: code block if (c == ':' && sci.ConfigurationLanguage == "haxe") { // Anonymous structures - ComaExpression coma = DisambiguateComa(sci, position, minPos); + var coma = DisambiguateComa(sci, position, minPos); if (coma == ComaExpression.FunctionDeclaration || coma == ComaExpression.VarDeclaration) { return ComaExpression.VarDeclaration; @@ -3968,31 +4053,24 @@ internal static ComaExpression DisambiguateComa(ScintillaControl sci, int positi } return ComaExpression.AnonymousObjectParam; } - else if (c != ')' && c != '}' && !Char.IsLetterOrDigit(c)) return ComaExpression.AnonymousObject; + if (c != ')' && c != '}' && !char.IsLetterOrDigit(c)) return ComaExpression.AnonymousObject; break; } } - else if (c == '}') - { - braceCount++; - } + else if (c == '}') braceCount++; else if (c == '?') { //TODO: Change to ASContext.Context.CurrentModel if (sci.ConfigurationLanguage == "haxe") // Haxe optional fields { - ComaExpression coma = DisambiguateComa(sci, position - 1, minPos); - if (coma == ComaExpression.FunctionDeclaration) - { - // Function optional argument - return coma; - } - else if (coma == ComaExpression.VarDeclaration) + var coma = DisambiguateComa(sci, position - 1, minPos); + if (coma == ComaExpression.FunctionDeclaration) return coma; // Function optional argument + if (coma == ComaExpression.VarDeclaration) { // Possible anonymous structure optional field. Check we are not in a ternary operator position--; - string word1 = GetWordLeft(sci, ref position); - c = (word1.Length > 0) ? word1[word1.Length - 1] : (char) sci.CharAt(position); + var word1 = GetWordLeft(sci, ref position); + c = word1.Length > 0 ? word1[word1.Length - 1] : (char) sci.CharAt(position); if (c == ',' || c == '{') return coma; } } @@ -4005,22 +4083,23 @@ internal static ComaExpression DisambiguateComa(ScintillaControl sci, int positi /// /// Parse function body for local var definitions - /// TODO ASComplete: parse coma separated local vars definitions + /// TODO ASComplete: parse coma separated local vars definitions /// /// Expression source /// Local vars dictionary (name, type) public static MemberList ParseLocalVars(ASExpr expression) { FileModel model; + var ctx = ASContext.Context; if (!string.IsNullOrEmpty(expression.FunctionBody)) { - MemberModel cm = expression.ContextMember; - string functionBody = Regex.Replace(expression.FunctionBody, "function\\s*\\(", "function __anonfunc__("); // name anonymous functions - model = ASContext.Context.GetCodeModel(functionBody); - int memberCount = model.Members.Count; - for (int memberIndex = 0; memberIndex < memberCount; memberIndex++) + var cm = expression.ContextMember; + var functionBody = Regex.Replace(expression.FunctionBody, "function\\s*\\(", "function __anonfunc__("); // name anonymous functions + model = ctx.GetCodeModel(functionBody, true); + var memberCount = model.Members.Count; + for (var memberIndex = 0; memberIndex < memberCount; memberIndex++) { - MemberModel member = model.Members[memberIndex]; + var member = model.Members[memberIndex]; if (cm.Equals(member)) continue; @@ -4028,125 +4107,124 @@ public static MemberList ParseLocalVars(ASExpr expression) member.LineFrom += expression.FunctionOffset; member.LineTo += expression.FunctionOffset; - if ((member.Flags & FlagType.Function) == FlagType.Function) + if ((member.Flags & FlagType.Function) != FlagType.Function) continue; + if (member.Name == "__anonfunc__") { - if (member.Name == "__anonfunc__") - { - model.Members.Remove(member); - memberCount--; - memberIndex--; - } - - if (member.Parameters == null) continue; - - foreach (MemberModel parameter in member.Parameters) - { - parameter.LineFrom += expression.FunctionOffset; - parameter.LineTo += expression.FunctionOffset; - model.Members.Add(parameter); - } + model.Members.Remove(member); + memberCount--; + memberIndex--; + } + if (member.Parameters is null) continue; + foreach (var parameter in member.Parameters) + { + parameter.LineFrom += expression.FunctionOffset; + parameter.LineTo += expression.FunctionOffset; + model.Members.Add(parameter); } } } else model = new FileModel(); - if (expression.ContextFunction != null && expression.ContextFunction.Parameters != null) + model.Members.Sort(); + if (expression.ContextFunction?.Parameters != null) { - ContextFeatures features = ASContext.Context.Features; - foreach (MemberModel item in expression.ContextFunction.Parameters) - { - if (item.Name.StartsWithOrdinal(features.dot)) - model.Members.Merge(new MemberModel(item.Name.Substring(item.Name.LastIndexOfOrdinal(features.dot) + 1), "Array", item.Flags, item.Access)); - else if (item.Name[0] == '?') model.Members.Merge(new MemberModel(item.Name.Substring(1), item.Type, item.Flags, item.Access)); - else model.Members.Merge(item); - } - if (features.functionArguments != null) - model.Members.Add(ASContext.Context.Features.functionArguments); + ctx.CodeComplete.ParseLocalVars(expression, model); + var arguments = ctx.Features.functionArguments; + if (arguments != null) model.Members.MergeByLine(arguments); } - model.Members.Sort(); return model.Members; } + protected virtual void ParseLocalVars(ASExpr expression, FileModel model) + { + var dot = ASContext.Context.Features.dot; + foreach (var item in expression.ContextFunction.Parameters) + { + var name = item.Name; + if (name.StartsWithOrdinal(dot)) model.Members.MergeByLine(new MemberModel(name.Substring(name.LastIndexOfOrdinal(dot) + 1), "Array", item.Flags, item.Access)); + else model.Members.MergeByLine(item); + } + } + /// /// Extract sub-expressions /// - private static string ExtractSubex(Match m) + static string ExtractSubex(Match m) { ExtractedSubex.Add(m.Value); return ".#" + (ExtractedSubex.Count - 1) + "~"; - } + } #endregion - + #region tools_functions - - /// - /// Text style is a literal. - /// - public static bool IsLiteralStyle(int style) - { - return IsNumericStyle(style) || IsStringStyle(style) || IsCharStyle(style); - } - - /// - /// Text style is a numeric literal. - /// - public static bool IsNumericStyle(int style) - { - return style == 4; - } - - /// - /// Text style is a string literal. - /// - public static bool IsStringStyle(int style) - { - return style == 6; - } - - /// - /// Text style is character literal. - /// - public static bool IsCharStyle(int style) - { - return style == 7; - } + + /// + /// Text style is a literal. + /// + public static bool IsLiteralStyle(int style) => IsNumericStyle(style) || IsStringStyle(style) || IsCharStyle(style); + + /// + /// Text style is a numeric literal. + /// + public static bool IsNumericStyle(int style) => style == (int) CPP.NUMBER; + + /// + /// Text style is a string literal. + /// + public static bool IsStringStyle(int style) => style == (int) CPP.STRING; + + /// + /// Text style is a multiline string literal. + /// + protected virtual bool IsMultilineStringStyle(ScintillaControl sci, int position) + { + return false; + } + + /// + /// Text style is character literal. + /// + public static bool IsCharStyle(int style) => style == (int) CPP.CHARACTER; /// /// Text is word /// public static bool IsTextStyle(int style) { - return style == 0 || style == 10 /*punctuation*/ || style == 11 /*identifier*/ - || style == 16 /*word2 (secondary keywords: class name)*/ - || style == 24 /*word4 (add keywords4)*/ || style == 25 /*word5 (add keywords5)*/ - || style == 127 /*PHP*/; + return style == (int) CPP.DEFAULT + || style == (int) CPP.OPERATOR + || style == (int) CPP.IDENTIFIER + || style == (int) CPP.WORD2 + || style == (int) CPP.WORD4 + || style == (int) CPP.WORD5 + || style == (int) HTML.PHP_OPERATOR; } /// /// Text is word or keyword /// public static bool IsTextStyleEx(int style) - { - return style == 0 || style == 5 /*word (secondary keywords)*/ - || style == 10 /*punctuation*/ || style == 11 /*identifier*/ - || style == 16 /*word2 (secondary keywords: class name)*/ - || style == 19 /*globalclass (primary keywords)*/ || style == 23 /*word3 (add keywords3)*/ - || style == 24 /*word4 (add keywords4)*/ || style == 25 /*word5 (add keywords5)*/ - || style == 127 /*PHP*/; - } + => IsTextStyle(style) + || style == (int) CPP.WORD + || style == (int) CPP.GLOBALCLASS + || style == (int) CPP.WORD3; public static bool IsCommentStyle(int style) - { - return style == 1 || style == 2 || style == 3 /*comments*/ - || style == 17 || style == 18 /*javadoc tags*/; - } + => style == (int) CPP.COMMENT + || style == (int) CPP.COMMENTLINE + || style == (int) CPP.COMMENTDOC + || style == (int) CPP.COMMENTDOCKEYWORD + || style == (int) CPP.COMMENTDOCKEYWORDERROR; + + public virtual bool IsRegexStyle(ScintillaControl sci, int position) + => sci.BaseStyleAt(position) == (int) CPP.REGEX; + + public static string GetWordLeft(ScintillaControl sci, int position) => GetWordLeft(sci, ref position); public static string GetWordLeft(ScintillaControl sci, ref int position) { - // get the word characters from the syntax definition - string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; - string word = ""; - //string exclude = "(){};,+*/\\=:.%\"<>"; - bool skipWS = true; + var characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; + var word = new StringBuilder(); + var skipWS = true; while (position >= 0) { var style = sci.BaseStyleAt(position); @@ -4155,83 +4233,202 @@ public static string GetWordLeft(ScintillaControl sci, ref int position) var c = (char)sci.CharAt(position); if (c <= ' ') { - if (!skipWS) - break; + if (!skipWS) break; } - else if (characterClass.IndexOf(c) < 0) break; + else if (!characterClass.Contains(c)) break; else if (style != 6) { - word = c + word; + word.Insert(0, c); skipWS = false; } } position--; } - return word; + return word.ToString(); } - public static ASResult GetExpressionType(ScintillaControl sci, int position) => GetExpressionType(sci, position, true); - - public static ASResult GetExpressionType(ScintillaControl sci, int position, bool filterVisibility) => GetExpressionType(sci, position, true, false); + public static string GetWordRight(ScintillaControl sci, int position) => GetWordRight(sci, ref position); - public static ASResult GetExpressionType(ScintillaControl sci, int position, bool filterVisibility, bool ignoreWhiteSpace) + public static string GetWordRight(ScintillaControl sci, ref int position) { - // context - int line = sci.LineFromPosition(position); - if (line != ASContext.Context.CurrentLine) - ASContext.Context.UpdateContext(line); - try + var characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; + var word = new StringBuilder(); + var skipWS = true; + var length = sci.Length; + while (position < length) { - ASExpr expr = GetExpression(sci, position, ignoreWhiteSpace); - expr.LocalVars = ParseLocalVars(expr); - if (string.IsNullOrEmpty(expr.Value)) + var style = sci.BaseStyleAt(position); + if (IsTextStyleEx(style)) { - ASResult res = new ASResult(); - res.Context = expr; - return res; + var c = (char)sci.CharAt(position); + if (c <= ' ') + { + if (!skipWS) break; + } + else if (!characterClass.Contains(c)) break; + else if (style != 6) + { + word.Append(c); + skipWS = false; + } } - FileModel aFile = ASContext.Context.CurrentModel; - ClassModel aClass = ASContext.Context.CurrentClass; - // Expression before cursor - return EvalExpression(expr.Value, expr, aFile, aClass, true, false, filterVisibility); + position++; } - finally + return word.ToString(); + } + + protected static void GetOperatorLeft(ScintillaControl sci, int position, ASExpr expression) + { + if (expression.Separator == " " || (expression.Separator == ";" && sci.CharAt(position) != ';')) { - // restore context - if (line != ASContext.Context.CurrentLine) - ASContext.Context.UpdateContext(ASContext.Context.CurrentLine); + var @operator = GetOperatorLeft(sci, ref position); + if (@operator.Length == 0) return; + expression.Separator = @operator; + expression.SeparatorPosition = position + 1; } } - private static MemberList GetTypeParameters(MemberModel model) + protected static string GetOperatorLeft(ScintillaControl sci, ref int position) { - MemberList retVal = null; - string template = model.Template; - if (template != null && template.StartsWith("<")) + var result = string.Empty; + var skipWS = true; + while (position >= 0) { - var sb = new StringBuilder(); - int groupCount = 0; - bool inConstraint = false; - MemberModel genType = null; - for (int i = 1, count = template.Length - 1; i < count; i++) + var c = (char)sci.CharAt(position); + if (char.IsDigit(c)) break; + var style = sci.BaseStyleAt(position); + if (IsTextStyleEx(style)) { - char c = template[i]; - if (!inConstraint) + if (c <= ' ') { - if (c == ':' || c == ',') - { - genType = new MemberModel(); - genType.Name = sb.ToString(); - genType.Type = sb.ToString(); - genType.Flags = FlagType.TypeDef; - inConstraint = c == ':'; - if (retVal == null) retVal = new MemberList(); - retVal.Add(genType); - sb.Length = 0; + if (!skipWS) break; + } + else if (char.IsLetterOrDigit(c) + || c == '.' || c == ',' || c == ';' || c == '_' || c == '$' + || c == '"' || c == '\'' + || c == ')' || c == '(' + || c == ']' || c == '[' + || c == '}' || c == '{') break; + else + { + skipWS = false; + result = c + result; + } + } + --position; + } + return result; + } + + public static char GetCharLeft(ScintillaControl sci, int position) => GetCharLeft(sci, true, ref position); + + public static char GetCharLeft(ScintillaControl sci, ref int position) => GetCharLeft(sci, true, ref position); + + public static char GetCharLeft(ScintillaControl sci, bool skipWhiteSpace, int position) => GetCharLeft(sci, skipWhiteSpace, ref position); + + public static char GetCharLeft(ScintillaControl sci, bool skipWhiteSpace, ref int position) + { + var result = position - 1; + while (result >= 0) + { + if (!sci.PositionIsOnComment(result)) + { + var c = (char) sci.CharAt(result); + if (!skipWhiteSpace || c > ' ') + { + position = result; + return c; + } + } + --result; + } + position = -1; + return ' '; + } + + public static char GetCharRight(ScintillaControl sci, ref int position) => GetCharRight(sci, true, ref position); + + public static char GetCharRight(ScintillaControl sci, bool skipWhiteSpace, int position) => GetCharRight(sci, skipWhiteSpace, ref position); + + public static char GetCharRight(ScintillaControl sci, bool skipWhiteSpace, ref int position) + { + var length = sci.Length; + var result = position; + while (result < length) + { + if (!sci.PositionIsOnComment(result)) + { + var c = (char)sci.CharAt(result); + if (!skipWhiteSpace || c > ' ') + { + position = result; + return c; + } + } + ++result; + } + position = -1; + return ' '; + } + + public static ASResult GetExpressionType(ScintillaControl sci, int position) => GetExpressionType(sci, position, true); + + public static ASResult GetExpressionType(ScintillaControl sci, int position, bool filterVisibility) => GetExpressionType(sci, position, filterVisibility, false); + + public static ASResult GetExpressionType(ScintillaControl sci, int position, bool filterVisibility, bool ignoreWhiteSpace) + { + // context + int line = sci.LineFromPosition(position); + if (line != ASContext.Context.CurrentLine) + ASContext.Context.UpdateContext(line); + try + { + var expr = GetExpression(sci, position, ignoreWhiteSpace); + expr.LocalVars = ParseLocalVars(expr); + if (string.IsNullOrEmpty(expr.Value)) return new ASResult {Context = expr}; + var aFile = ASContext.Context.CurrentModel; + var aClass = ASContext.Context.CurrentClass; + // Expression before cursor + return ASContext.Context.CodeComplete.EvalExpression(expr.Value, expr, aFile, aClass, true, false, filterVisibility); + } + finally + { + // restore context + if (line != ASContext.Context.CurrentLine) + ASContext.Context.UpdateContext(ASContext.Context.CurrentLine); + } + } + static MemberList GetTypeParameters(MemberModel model) + { + MemberList result = null; + var template = model.Template; + if (template != null && template.StartsWith('<')) + { + var sb = new StringBuilder(); + int groupCount = 0; + bool inConstraint = false; + MemberModel genType = null; + for (int i = 1, count = template.Length - 1; i < count; i++) + { + char c = template[i]; + if (!inConstraint) + { + if (c == ':' || c == ',') + { + genType = new MemberModel + { + Name = sb.ToString(), + Type = sb.ToString(), + Flags = FlagType.TypeDef + }; + inConstraint = c == ':'; + result ??= new MemberList(); + result.Add(genType); + sb.Length = 0; continue; } - else if (char.IsWhiteSpace(c)) continue; + if (char.IsWhiteSpace(c)) continue; sb.Append(c); } else @@ -4240,456 +4437,507 @@ private static MemberList GetTypeParameters(MemberModel model) { if (groupCount == 0) { - genType.Type += ":" + sb.ToString(); + genType.Type += ":" + sb; genType = null; inConstraint = false; sb.Length = 0; continue; } } - else if ("({[<".IndexOf(c) > -1) - groupCount++; - else if (")}]>".IndexOf(c) > -1) - groupCount--; + else if ("({[<".Contains(c)) groupCount++; + else if (")}]>".Contains(c)) groupCount--; sb.Append(c); } } if (sb.Length > 0) { - if (retVal == null) retVal = new MemberList(); + result ??= new MemberList(); if (!inConstraint) - retVal.Add(new MemberModel { Name = sb.ToString(), Type = sb.ToString(), Flags = FlagType.TypeDef }); - else - genType.Type += ":" + sb.ToString(); + { + var name = sb.ToString(); + result.Add(new MemberModel {Name = name, Type = name, Flags = FlagType.TypeDef}); + } + else genType.Type += ":" + sb; } } - - return retVal; + return result; } - static private List GetAllClasses(ScintillaControl sci, bool classesOnly, bool showClassVars) - { - MemberList known = ASContext.Context.GetAllProjectClasses(); - if (known.Count == 0) return null; - - // get local Class vars - if (showClassVars) - { - MemberList found = new MemberList(); - - ASExpr expr = GetExpression(sci, sci.CurrentPos); - if (expr.Value != null) - { - MemberList locals = ParseLocalVars(expr); - foreach (MemberModel local in locals) - if (local.Type == "Class") - found.Add(local); - } - - if (found.Count > 0) - { - found.Sort(); - found.Merge(known); - known = found; - } - } - - if (!ASContext.Context.CurrentClass.IsVoid()) - { - if (ASContext.Context.Features.hasDelegates) - { - MemberList delegates = new MemberList(); - - foreach (MemberModel field in ASContext.Context.CurrentClass.Members) - if ((field.Flags & FlagType.Delegate) > 0) - delegates.Add(field); - - if (delegates.Count > 0) - { - delegates.Sort(); - delegates.Merge(known); - known = delegates; - } - } - - if (ASContext.Context.Features.hasGenerics) - { - var typeParams = GetVisibleTypeParameters(); - - if (typeParams != null && typeParams.Items.Count > 0) - { - typeParams.Sort(); - typeParams.Merge(known); - known = typeParams; - } - } - } - - List list = new List(); - string prev = null; - FlagType mask = (classesOnly) ? - FlagType.Class | FlagType.Interface | FlagType.Enum | FlagType.Delegate | FlagType.Struct | FlagType.TypeDef - : (FlagType)uint.MaxValue; - foreach (MemberModel member in known) - { - if ((member.Flags & mask) == 0 || prev == member.Name) - if (!showClassVars || member.Type != "Class") continue; - prev = member.Name; - list.Add(new MemberItem(member)); - } - - return list; - } - - private static MemberList GetVisibleElements() + static List GetAllClasses(ScintillaControl sci, bool classesOnly, bool showClassVars) { - MemberList known = ASContext.Context.GetVisibleExternalElements(); + var ctx = ASContext.Context; + var known = ctx.GetAllProjectClasses(); + if (known.Count == 0) return null; - if (ASContext.Context.Features.hasGenerics && !ASContext.Context.CurrentClass.IsVoid()) + // get local Class vars + if (showClassVars) { - var typeParams = GetVisibleTypeParameters(); + var found = new MemberList(); - if (typeParams != null && typeParams.Count > 0) + var expr = GetExpression(sci, sci.CurrentPos); + if (expr.Value != null) { - typeParams.Sort(); - typeParams.Merge(known); - - known = typeParams; + var list = ParseLocalVars(expr); + foreach (var it in list) + if (it.Type == "Class") + found.Add(it); } - } - - return known; - } - private static MemberList GetVisibleTypeParameters() - { - var typeParams = GetTypeParameters(ASContext.Context.CurrentClass); - - var curMember = ASContext.Context.CurrentMember; - if (curMember != null && (curMember.Flags & FlagType.Function) > 0) - { - var memberTypeParams = GetTypeParameters(curMember); - if (typeParams != null && memberTypeParams != null) - typeParams.Add(memberTypeParams); - else if (typeParams == null) - typeParams = memberTypeParams; + if (found.Count > 0) + { + found.Sort(); + found.Merge(known); + known = found; + } } - return typeParams; - } - - /// - /// Returns whether or not position is inside of an expression - /// block in Haxe String interpolation ('${expr}') - /// - public static bool IsInterpolationExpr(ScintillaControl sci, int position) - { - if (ASContext.Context.Features.hasStringInterpolation) + if (!ctx.CurrentClass.IsVoid()) { - char stringChar = sci.GetStringType(position - 1); - if (ASContext.Context.Features.stringInterpolationQuotes.Contains(stringChar)) + if (ctx.Features.hasDelegates) { - char current = (char) sci.CharAt(position); + var delegates = new MemberList(); + + foreach (var field in ctx.CurrentClass.Members) + if ((field.Flags & FlagType.Delegate) > 0) + delegates.Add(field); - for (int i = position - 1; i >= 0; i--) + if (delegates.Count > 0) { - var next = current; - current = (char) sci.CharAt(i); + delegates.Sort(); + delegates.Merge(known); + known = delegates; + } + } - if (current == stringChar) - { - if (!IsEscapedCharacter(sci, i)) break; - } - else if (current == '$') - { - if (next == '{' && !IsEscapedCharacter(sci, i, '$')) return true; - } - else if (current == '}') - { - i = sci.BraceMatch(i); - current = (char) sci.CharAt(i); - if (i > 0 && current == '{' && sci.CharAt(i - 1) == '$') break; - } + if (ctx.Features.hasGenerics) + { + var typeParams = GetVisibleTypeParameters(); + if (!typeParams.IsNullOrEmpty()) + { + typeParams.Sort(); + typeParams.Merge(known); + known = typeParams; } } } - return false; + + var result = new List(); + string prev = null; + var mask = (classesOnly) + ? FlagType.Class | FlagType.Interface | FlagType.Enum | FlagType.Delegate | FlagType.Struct | FlagType.TypeDef + : (FlagType)uint.MaxValue; + foreach (var member in known) + { + if ((member.Flags & mask) == 0 || prev == member.Name) + if (!showClassVars || member.Type != "Class") continue; + prev = member.Name; + result.Add(new MemberItem(member)); + } + return result; } - private static bool IsEscapedCharacter(ScintillaControl sci, int position, char escapeChar = '\\') + static MemberList GetVisibleElements() { - bool escaped = false; - - for (int i = position - 1; i >= 0; i--) + var result = ASContext.Context.GetVisibleExternalElements(); + if (ASContext.Context.Features.hasGenerics && !ASContext.Context.CurrentClass.IsVoid() + && GetVisibleTypeParameters() is {Count: > 0} @params) { - if (sci.CharAt(i) != escapeChar) break; - escaped = !escaped; + @params.Sort(); + @params.Merge(result); + return @params; } - - return escaped; + return result; } - private static bool IsMatchingQuote(char quote, int style) + static MemberList GetVisibleTypeParameters() { - return quote == '"' && IsStringStyle(style) || quote == '\'' && IsCharStyle(style); + var result = GetTypeParameters(ASContext.Context.CurrentClass); + var member = ASContext.Context.CurrentMember; + if (member != null && (member.Flags & FlagType.Function) > 0) + { + var @params = GetTypeParameters(member); + if (result != null && @params != null) result.Add(@params); + else if (result is null) result = @params; + } + return result; } /// - /// Whether the character at the position is inside of the - /// brackets of haxe metadata (@:allow(path) etc) + /// Returns whether or not position is inside of an expression block in String interpolation + /// Scintilla Control + /// Cursor position /// - private static bool IsMetadataArgument(ScintillaControl sci, int position) - { - if (!ASContext.Context.CurrentModel.haXe || ASContext.Context.CurrentMember != null) - return false; - - char c = ' '; - char next = (char)sci.CharAt(position); - bool openingBracket = false; + public virtual bool IsStringInterpolationStyle(ScintillaControl sci, int position) => false; - for (int i = position; i > 0; i--) + protected bool IsEscapedCharacter(ScintillaControl sci, int position, char escapeChar = '\\') + { + var result = false; + for (var i = position - 1; i >= 0; i--) { - c = next; - next = (char)sci.CharAt(i); - - if (c == ')' || c == '}' || c == ';') - return false; - if (c == '(') - openingBracket = true; - if (openingBracket && c == ':' && next == '@') - return true; + if (sci.CharAt(i) != escapeChar) break; + result = !result; } - return false; + return result; } - private static bool IsXmlType(ClassModel model) - { - return model != null - && (model.QualifiedName == "XML" || model.QualifiedName == "XMLList"); - } + static bool IsMatchingQuote(char quote, int style) => quote == '"' && IsStringStyle(style) || quote == '\'' && IsCharStyle(style); + + protected virtual bool IsMetadataArgument(ScintillaControl sci, int position) => false; + + static bool IsXmlType(ClassModel model) => model != null && (model.QualifiedName == "XML" || model.QualifiedName == "XMLList"); - public static int ExpressionEndPosition(ScintillaControl sci, int position) + public static int ExpressionEndPosition(ScintillaControl sci, int position) => ExpressionEndPosition(sci, position, false); + + public static int ExpressionEndPosition(ScintillaControl sci, int position, bool skipWhiteSpace) { var member = ASContext.Context.CurrentMember; var endPosition = member != null ? sci.LineEndPosition(member.LineTo) : sci.TextLength; - return ExpressionEndPosition(sci, position, endPosition); + return ExpressionEndPosition(sci, position, endPosition, skipWhiteSpace); } - public static int ExpressionEndPosition(ScintillaControl sci, int startPos, int endPos) + public static int ExpressionEndPosition(ScintillaControl sci, int startPos, int endPos) => ExpressionEndPosition(sci, startPos, endPos, false); + + public static int ExpressionEndPosition(ScintillaControl sci, int startPos, int endPos, bool skipWhiteSpace) { + var word = GetWordLeft(sci, sci.WordStartPosition(startPos, true) - 1); + var ctx = ASContext.Context; + if (ctx.Features.declKeywords.Contains(word) || ctx.Features.typesKeywords.Contains(word)) return sci.WordEndPosition(startPos, true); + var isInStringInterpolation = ctx.CodeComplete.IsStringInterpolationStyle(sci, startPos); var result = startPos; var statementEnd = startPos; var characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; - var groupCount = 0; + var parCount = 0; var brCount = 0; var arrCount = 0; + var dQuotes = 0; + var sQuotes = 0; var hadWS = false; + var stop = false; + var exprStarted = false; sci.Colourise(0, -1); while (statementEnd < endPos) { - if (sci.PositionIsOnComment(statementEnd) || sci.PositionIsInString(statementEnd)) + if (sci.PositionIsOnComment(statementEnd)) { statementEnd++; continue; } - var c = (char) sci.CharAt(statementEnd++); - if (c == '(') groupCount++; + if (ctx.CodeComplete.IsRegexStyle(sci, statementEnd)) + { + statementEnd++; + result = statementEnd; + continue; + } + var c = (char)sci.CharAt(statementEnd); + #region PositionIsInMultilineString + if ((dQuotes > 0 && c != '\"') || (sQuotes > 0 && c != '\'')) + { + result = ++statementEnd; + continue; + } + if (dQuotes > 0 && c == '\"') + { + result = ++statementEnd; + if (!ctx.CodeComplete.IsEscapedCharacter(sci, statementEnd - 1) && --dQuotes <= 0) break; + continue; + } + if (sQuotes > 0 && c == '\'') + { + result = ++statementEnd; + if (!ctx.CodeComplete.IsEscapedCharacter(sci, statementEnd - 1) && --sQuotes <= 0) break; + continue; + } + #endregion PositionIsInMultilineString + if (sci.PositionIsInString(statementEnd) && !ctx.CodeComplete.IsStringInterpolationStyle(sci, statementEnd)) + { + if (isInStringInterpolation) + { + result = statementEnd - 1; + break; + } + result = ++statementEnd; + continue; + } + statementEnd++; + if (c == '(') + { + if (arrCount == 0 && brCount == 0) + { + parCount++; + exprStarted = true; + } + } else if (c == ')') { - groupCount--; - if (groupCount == 0) result = statementEnd; - if (groupCount <= 0) break; + if (arrCount == 0 && brCount == 0) + { + parCount--; + if (parCount == 0) result = statementEnd; + if (parCount < 0) break; + } + } + else if (c == '{') + { + if (parCount == 0 && arrCount == 0) + { + if (stop) break; + brCount++; + exprStarted = true; + } } - else if (c == '{' && groupCount > 0) brCount++; else if (c == '}') { - brCount--; - if (brCount < 0) break; + if (parCount == 0 && arrCount == 0) + { + brCount--; + if (brCount == 0) result = statementEnd; + if (brCount < 0) break; + } } - else if (c == '[' && groupCount > 0) arrCount++; - else if (c == ']') + else if (c == '[') { - arrCount--; - if (arrCount < 0) break; + if (parCount == 0 && brCount == 0) + { + // for example: ''.split()[] + if (GetCharLeft(sci, statementEnd - 2) == ')') + { + result = statementEnd - 1; + break; + } + if (stop) break; + arrCount++; + exprStarted = true; + } } - else if (c == ';') + else if (c == ']') { - if (brCount == 0) break; + if (parCount == 0 && brCount == 0) + { + arrCount--; + if (arrCount == 0) result = statementEnd; + if (arrCount < 0) break; + } } - else if (groupCount == 0) + else if (parCount == 0 && arrCount == 0 && brCount == 0) { + if (dQuotes == 0 && c == '\'') + { + result = ++statementEnd; + if (sQuotes == 0) sQuotes++; + else sQuotes--; + continue; + } + if (sQuotes > 0) continue; + if (sQuotes == 0 && c == '"') + { + result = ++statementEnd; + if (dQuotes == 0) dQuotes++; + else dQuotes--; + continue; + } + if (dQuotes > 0) continue; if (characterClass.Contains(c)) { - if (hadWS) break; + if (skipWhiteSpace) + { + skipWhiteSpace = false; + hadWS = false; + } + else if (hadWS) break; + stop = true; result = statementEnd; + exprStarted = true; } else if (c <= ' ') hadWS = true; + else if (c == '.') + { + // for example: 0.0 + if (!exprStarted) break; + if (statementEnd >= endPos || !char.IsDigit((char) sci.CharAt(statementEnd))) break; + var p = statementEnd - 2; + if (p < 0 || !char.IsDigit((char) sci.CharAt(p))) break; + } + else if (c == '-' || c == '+') + { + if (!exprStarted) continue; + var p = statementEnd - 2; + // for example: 5e-324 + if (p < 1 || (sci.CharAt(p) != 'e' && !char.IsDigit((char) sci.CharAt(p - 1)))) break; + } else break; } } return result; } + /// + /// Returns true if position is before body of class or member + /// + public bool PositionIsBeforeBody(ScintillaControl sci, int position, MemberModel member) + { + var groupCount = 0; + var positionFrom = sci.PositionFromLine(member.LineFrom); + for (var i = positionFrom; i < position; i++) + { + if (sci.PositionIsOnComment(position)) continue; + var c = (char)sci.CharAt(i); + if (c == '(' || c == '<') groupCount++; + else if (c == ')' || (c == '>' && sci.CharAt(i - 1) != '-')) groupCount--; + else if (c == '{' && groupCount == 0) return false; + } + return true; + } + #endregion #region tooltips formatting - static public string GetCodeTipCode(ASResult result) - { - if (result.Member == null) - { - return result.Type != null ? result.Type.ToString() : null; - } - - var file = GetFileContents(result.InFile); - if (string.IsNullOrEmpty(file)) - { - return MemberTooltipText(result.Member, ClassModel.VoidClass); - } - - int eolMode = LineEndDetector.DetectNewLineMarker(file, (Int32)PluginBase.MainForm.Settings.EOLMode); - var eolMarker = LineEndDetector.GetNewLineMarker(eolMode); - var lines = file.Split(new[] { eolMarker }, StringSplitOptions.None); - var code = new StringBuilder(); - for (var index = result.Member.LineFrom; index < result.Member.LineTo; index++) - { - code.AppendLine(lines[index]); - } - code.Append(lines[result.Member.LineTo]); - return code.ToString(); - } - - static private string GetFileContents(FileModel model) - { - if (model != null && model.FileName.Length > 0 && File.Exists(model.FileName)) - { - foreach (ITabbedDocument doc in PluginBase.MainForm.Documents) - { - if (doc.IsEditable && doc.FileName.ToUpper() == model.FileName.ToUpper()) - { - return doc.SciControl.Text; - } - } - var info = FileHelper.GetEncodingFileInfo(model.FileName); - return info != null ? info.Contents : null; - } - return null; + public static string GetCodeTipCode(ASResult result) + { + if (result.Member is null) return result.Type?.ToString(); + + var file = GetFileContents(result.InFile); + if (string.IsNullOrEmpty(file)) return MemberTooltipText(result.Member, ClassModel.VoidClass); + var eolMode = LineEndDetector.DetectNewLineMarker(file); + var eolMarker = LineEndDetector.GetNewLineMarker(eolMode); + var lines = file.Split(new[] { eolMarker }, StringSplitOptions.None); + var code = new StringBuilder(); + for (var index = result.Member.LineFrom; index < result.Member.LineTo; index++) + { + code.AppendLine(lines[index]); + } + code.Append(lines[result.Member.LineTo]); + return code.ToString(); + } + + static string GetFileContents(FileModel model) + { + if (!File.Exists(model?.FileName)) return null; + foreach (var doc in PluginBase.MainForm.Documents) + { + if (doc.SciControl is { } sci && string.Equals(sci.FileName, model.FileName, StringComparison.CurrentCultureIgnoreCase)) + { + return sci.Text; + } + } + var info = FileHelper.GetEncodingFileInfo(model.FileName); + return info.Contents; } - static public string GetToolTipText(ASResult result) + public static string GetToolTipText(ASResult expr) => ASContext.Context.CodeComplete.GetToolTipTextEx(expr); + + protected virtual string GetToolTipTextEx(ASResult expr) { - if (result.Member != null && result.InClass != null) + if (expr.IsNull()) return null; + if (expr.Member != null && expr.InClass != null) { - return MemberTooltipText(result.Member, result.InClass) + GetToolTipDoc(result.Member); + return MemberTooltipText(expr.Member, expr.InClass) + GetToolTipDoc(expr.Member); } - else if (result.Member != null && (result.Member.Flags & FlagType.Constructor) != FlagType.Constructor) + if (expr.Member != null && (expr.Member.Flags & FlagType.Constructor) != FlagType.Constructor) { - return MemberTooltipText(result.Member, ClassModel.VoidClass) + GetToolTipDoc(result.Member); + return MemberTooltipText(expr.Member, ClassModel.VoidClass) + GetToolTipDoc(expr.Member); } - else if (result.InClass != null) + if (expr.InClass != null) { - return ClassModel.ClassDeclaration(result.InClass) + GetToolTipDoc(result.InClass); + return ClassModel.ClassDeclaration(expr.InClass) + GetToolTipDoc(expr.InClass); } - else if (result.Type != null) + if (expr.Type != null) { - if (result.Context.WordBefore == "new") - { - var member = result.Type.Members.Search(result.Type.Name, FlagType.Constructor, 0); - if (member != null) return MemberTooltipText(member, result.Type) + GetToolTipDoc(member); - } - return ClassModel.ClassDeclaration(result.Type) + GetToolTipDoc(result.Type); + if (expr.Context.WordBefore == "new") return ASContext.Context.CodeComplete.GetConstructorTooltipText(expr.Type); + return ClassModel.ClassDeclaration(expr.Type) + GetToolTipDoc(expr.Type); } - else return null; + return null; } - private static string GetToolTipDoc(MemberModel model) + protected virtual string GetConstructorTooltipText(ClassModel type) { - string details = (UITools.Manager.ShowDetails) ? ASDocumentation.GetTipFullDetails(model, null) : ASDocumentation.GetTipShortDetails(model, null); - return details.TrimStart(new char[] { ' ', '\u2026' }); + var name = type.Name; + var member = type.Members.Search(name, FlagType.Constructor) + ?? new MemberModel(name, name, FlagType.Access | FlagType.Function | FlagType.Constructor, Visibility.Public); + return MemberTooltipText(member, type) + GetToolTipDoc(member); } - static private string MemberTooltipText(MemberModel member, ClassModel inClass) + protected static string GetToolTipDoc(MemberModel model) { - // modifiers - FlagType ft = member.Flags; - Visibility acc = member.Access; - string modifiers = ""; - if ((ft & FlagType.Class) == 0) - { - if ((ft & FlagType.LocalVar) > 0) - modifiers += "(local) "; - else if ((ft & FlagType.ParameterVar) > 0) - modifiers += "(parameter) "; - else if ((ft & FlagType.AutomaticVar) > 0) - modifiers += "(auto) "; - else - { - if ((ft & FlagType.Extern) > 0) - modifiers += "extern "; - if ((ft & FlagType.Native) > 0) - modifiers += "native "; - if ((ft & FlagType.Static) > 0) - modifiers += "static "; - if ((acc & Visibility.Private) > 0) - modifiers += "private "; - else if ((acc & Visibility.Public) > 0) - modifiers += "public "; - else if ((acc & Visibility.Protected) > 0) - modifiers += "protected "; - else if ((acc & Visibility.Internal) > 0) - modifiers += "internal "; - } - } + var details = UITools.Manager.ShowDetails + ? ASDocumentation.GetTipFullDetails(model, null) + : ASDocumentation.GetTipShortDetails(model, null); + return details.TrimStart(' ', '\u2026'); + } + + protected static string MemberTooltipText(MemberModel member, ClassModel inClass) + { + var modifiers = ASContext.Context.CodeComplete.GetMemberModifiersTooltipText(member); // signature - string foundIn = ""; + var foundIn = ""; if (inClass != ClassModel.VoidClass) { - Color themeForeColor = PluginBase.MainForm.GetThemeColor("MethodCallTip.InfoColor"); - string foreColorString = themeForeColor != Color.Empty ? ColorTranslator.ToHtml(themeForeColor) : "#666666:MULTIPLY"; + var themeForeColor = PluginBase.MainForm.GetThemeColor("MethodCallTip.InfoColor"); + var foreColorString = + themeForeColor != Color.Empty ? ColorTranslator.ToHtml(themeForeColor) : "#666666:MULTIPLY"; foundIn = "\n[COLOR=" + foreColorString + "]in " + MemberModel.FormatType(inClass.QualifiedName) + "[/COLOR]"; } - if ((ft & (FlagType.Getter | FlagType.Setter)) > 0) - return String.Format("{0}property {1}{2}", modifiers, member.ToString(), foundIn); - else if (ft == FlagType.Function) - return String.Format("{0}function {1}{2}", modifiers, member.ToString(), foundIn); - else if ((ft & FlagType.Namespace) > 0) - return String.Format("{0}namespace {1}{2}", modifiers, member.Name, foundIn); - else if ((ft & FlagType.Constant) > 0) + return ASContext.Context.CodeComplete.GetMemberSignatureTooltipText(member, modifiers, foundIn); + } + + protected virtual string GetMemberSignatureTooltipText(MemberModel member, string modifiers, string foundIn) + { + var ft = member.Flags; + if ((ft & (FlagType.Getter | FlagType.Setter)) > 0) return $"{modifiers}property {member}{foundIn}"; + if (ft == FlagType.Function) return $"{modifiers}function {member}{foundIn}"; + if ((ft & FlagType.Namespace) > 0) return $"{modifiers}namespace {member.Name}{foundIn}"; + if ((ft & FlagType.Constant) > 0) + { + if (member.Value is null) return $"{modifiers}const {member}{foundIn}"; + return $"{modifiers}const {member} = {member.Value}{foundIn}"; + } + + if ((ft & FlagType.Variable) > 0) return $"{modifiers}var {member}{foundIn}"; + if ((ft & FlagType.Delegate) > 0) return $"{modifiers}delegate {member}{foundIn}"; + return $"{modifiers}{member}{foundIn}"; + } + + protected virtual string GetMemberModifiersTooltipText(MemberModel member) + { + var result = string.Empty; + var flags = member.Flags; + if ((flags & FlagType.Class) == 0) { - if (member.Value == null) - return String.Format("{0}const {1}{2}", modifiers, member.ToString(), foundIn); + if ((flags & FlagType.LocalVar) > 0) result += "(local) "; + else if ((flags & FlagType.ParameterVar) > 0) result += "(parameter) "; + else if ((flags & FlagType.AutomaticVar) > 0) result += "(auto) "; else - return String.Format("{0}const {1} = {2}{3}", modifiers, member.ToString(), member.Value, foundIn); + { + if ((flags & FlagType.Extern) > 0) result += "extern "; + if ((flags & FlagType.Native) > 0) result += "native "; + if ((flags & FlagType.Static) > 0) result += "static "; + var access = member.Access; + if ((access & Visibility.Private) > 0) result += "private "; + else if ((access & Visibility.Public) > 0) result += "public "; + else if ((access & Visibility.Protected) > 0) result += "protected "; + else if ((access & Visibility.Internal) > 0) result += "internal "; + } } - else if ((ft & FlagType.Variable) > 0) - return String.Format("{0}var {1}{2}", modifiers, member.ToString(), foundIn); - else if ((ft & FlagType.Delegate) > 0) - return String.Format("{0}delegate {1}{2}", modifiers, member.ToString(), foundIn); - else - return String.Format("{0}{1}{2}", modifiers, member.ToString(), foundIn); + return result; } + #endregion #region automatic code generation - static private ASExpr LastExpression; + + static ASExpr LastExpression; /// /// When typing a fully qualified class name: /// - automatically insert import statement /// - replace with short name /// - static internal void HandleCompletionInsert(ScintillaControl sci, int position, string text, char trigger, ICompletionListItem item) + internal static void HandleCompletionInsert(ScintillaControl sci, int position, string text, char trigger, ICompletionListItem item) { // if the current class hash was set, we want to store whatever the user selected as the last-completed member for this class. - if (currentClassHash != null) - { - completionHistory[currentClassHash] = text; - } - - if (!ASContext.Context.IsFileValid) - return; + if (currentClassHash != null) completionHistory[currentClassHash] = text; + if (!ASContext.Context.IsFileValid) return; // let the context handle the insertion - if (ASContext.Context.OnCompletionInsert(sci, position, text, trigger)) - return; + if (ASContext.Context.OnCompletionInsert(sci, position, text, trigger)) return; // event inserted if (item is EventItem) { @@ -4698,117 +4946,111 @@ static internal void HandleCompletionInsert(ScintillaControl sci, int position, } // default handling - if (ASContext.Context.Settings != null) + if (ASContext.Context.Settings is null) return; + var textEndPosition = position + text.Length; + // was a fully qualified type inserted? + var expr = GetExpression(sci, textEndPosition); + if (expr.Value is null) return; + var type = GetExpressionType(sci, textEndPosition); + if (type.IsPackage) return; + var features = ASContext.Context.Features; + // add ; for imports + if ((trigger == ' ' || trigger == '\n' || trigger == '\t') + && expr.WordBefore != null + && (expr.WordBefore == features.importKey || expr.WordBefore == features.importKeyAlt)) + { + if (!sci.GetLine(sci.CurrentLine).Contains(';')) sci.InsertText(sci.CurrentPos, ";"); + return; + } + // look for a snippet + if (!expr.Value.Contains(features.dot)) { - int textEndPosition = position + text.Length; - // was a fully qualified type inserted? - ASExpr expr = GetExpression(sci, textEndPosition); - if (expr.Value == null) return; - ASResult type = GetExpressionType(sci, textEndPosition); - if (type.IsPackage) return; - ContextFeatures features = ASContext.Context.Features; - - // add ; for imports - if (" \n\t".IndexOf(trigger) >= 0 && expr.WordBefore != null - && (expr.WordBefore == features.importKey || expr.WordBefore == features.importKeyAlt)) - { - if (!sci.GetLine(sci.CurrentLine).Contains(";")) sci.InsertText(sci.CurrentPos, ";"); - return; - } - - // look for a snippet - if (trigger == '\t' && expr.Value.IndexOfOrdinal(features.dot) < 0) + if (trigger == '\t') { - foreach(string key in features.codeKeywords) + foreach(var key in features.codeKeywords) if (key == expr.Value) { InsertSnippet(key); return; } } + if (trigger != ' ' + // for example: priv$(EntryPoint) -> private $(EntryPoint) + && (features.accessKeywords.Contains(text) + // for example: va$(EntryPoint) -> var $(EntryPoint) + || text == features.varKey || text == features.constKey + // for example: re$(EntryPoint) -> return $(EntryPoint) + || text == features.ReturnKey + // for example: im$(EntryPoint) -> import $(EntryPoint) + || features.typesPreKeys.Contains(text) + // for example: cl$(EntryPoint) -> class $(EntryPoint) + || features.typesKeywords.Contains(text))) + { + if (text == features.ReturnKey) + { + var returnType = expr.ContextFunction?.Type; + if (returnType.IsNullOrEmpty() || returnType == features.voidKey) + { + return; + } + } - // resolve context & do smart insertion - expr.LocalVars = ParseLocalVars(expr); - ASResult context = EvalExpression(expr.Value, expr, ASContext.Context.CurrentModel, ASContext.Context.CurrentClass, true, false); - if (SmartInsertion(sci, position, expr, context)) - DispatchInsertedElement(context, trigger); + var pos = sci.CurrentPos; + sci.InsertText(pos++, " "); + sci.SetSel(pos, pos); + OnChar(sci, ' ', true); + return; + } } + // resolve context & do smart insertion + expr.LocalVars = ParseLocalVars(expr); + var context = EvalExpression(expr.Value, expr, ASContext.Context.CurrentModel, ASContext.Context.CurrentClass, true, false); + if (SmartInsertion(sci, position, expr, context)) + DispatchInsertedElement(context, trigger); } - private static void SmartEventInsertion(ScintillaControl sci, int position, ICompletionListItem item) + static void SmartEventInsertion(ScintillaControl sci, int position, ICompletionListItem item) { if (!ASContext.Context.Settings.GenerateImports) return; try { - ClassModel import = (item as EventItem).EventType; - if (!ASContext.Context.IsImported(import, sci.LineFromPosition(position))) - { - int offset = ASGenerator.InsertImport(import, true); - if (offset > 0) - { - position += offset; - sci.SetSel(position, position); - } - } + var import = ((EventItem) item).EventType; + if (ASContext.Context.IsImported(import, sci.LineFromPosition(position))) return; + var offset = ASGenerator.InsertImport(import, true); + if (offset <= 0) return; + position += offset; + sci.SetSel(position, position); } - catch (Exception) // event type name already present in imports + catch // event type name already present in imports { } } - private static bool SmartInsertion(ScintillaControl sci, int position, ASExpr expr, ASResult context) + static bool SmartInsertion(ScintillaControl sci, int position, ASExpr expr, ASResult context) { - ContextFeatures features = ASContext.Context.Features; - FileModel cFile = ASContext.Context.CurrentModel; - FileModel inFile = null; - MemberModel import = null; + var features = ASContext.Context.Features; + var cFile = ASContext.Context.CurrentModel; + MemberModel import = context.Type; // if completed a package-level member - if (context.Member != null && context.Member.IsPackageLevel && context.Member.InFile.Package != "") + if (context.Member != null && context.Member.IsPackageLevel && context.Member.InFile.Package.Length != 0) { - inFile = context.Member.InFile; - import = context.Member.Clone() as MemberModel; - import.Type = inFile.Package + "." + import.Name; + import = context.Member.Clone(); + import.Type = context.Member.InFile.Package + "." + import.Name; } // if not completed a type - else if (context.IsNull() || !context.IsStatic || context.Type == null - || (context.Type.Type != null && context.Type.Type.IndexOfOrdinal(features.dot) < 0) - || context.Type.IsVoid()) + else if (context.IsNull() || !context.IsStatic || context.Type is null + || (context.Type.Type != null && !context.Type.Type.Contains(features.dot)) + || context.Type.IsVoid()) { - if (context.Member != null && expr.Separator == " " - && expr.WordBefore == features.overrideKey) + if (context.Member != null && expr.Separator == " " && expr.WordBefore == features.overrideKey) { ASGenerator.GenerateOverride(sci, context.InClass, context.Member, position); return false; } - /*else if (context.Member != null && cMember == null && !context.inClass.IsVoid()) - { - string ins = features.overrideKey + " "; - string w = sci.GetWordFromPosition(position); - sci.SetSel(position, position); - sci.ReplaceSel(ins); - position = position + ins.Length; - sci.CurrentPos = position; - sci.SetSel(position, position); - ASGenerator.GenerateOverride(sci, context.inClass, context.Member, position); - return false; - }*/ - else if (!context.IsNull()) - { - if (expr.WordBefore == features.importKey) - ASContext.Context.RefreshContextCache(expr.Value); - } + if (!context.IsNull() && expr.WordBefore == features.importKey) ASContext.Context.RefreshContextCache(expr.Value); return true; } - // test inserted type - else - { - inFile = context.InFile; - import = context.Type; - } - if (inFile == null || import == null) - return false; - if (expr.Separator == " " && !string.IsNullOrEmpty(expr.WordBefore)) { if (expr.WordBefore == features.importKey || expr.WordBefore == features.importKeyAlt @@ -4822,95 +5064,69 @@ private static bool SmartInsertion(ScintillaControl sci, int position, ASExpr ex int offset = 0; int startPos = expr.PositionExpression; int endPos = sci.CurrentPos; - - if (ASContext.Context.Settings.GenerateImports && shouldShortenType(sci, position, import, cFile, ref offset)) + if (ASContext.Context.Settings.GenerateImports && ShouldShortenType(sci, position, import, cFile, ref offset)) { // insert short name startPos += offset; endPos += offset; sci.SetSel(startPos, endPos); - sci.ReplaceSel(checkShortName(import.Name)); + sci.ReplaceSel(CheckShortName(import.Name)); sci.SetSel(sci.CurrentPos, sci.CurrentPos); } return true; } - private static bool shouldShortenType(ScintillaControl sci, int position, MemberModel import, FileModel cFile, ref int offset) + static bool ShouldShortenType(ScintillaControl sci, int position, MemberModel import, FileModel cFile, ref int offset) { - // check if in the same file or package - /*if (cFile == inFile || features.hasPackages && cFile.Package == inFile.Package) - return true*/ - - if (IsMetadataArgument(sci, position)) - return false; - - // type name already present in imports - try - { - int curLine = sci.LineFromPosition(position); - if (ASContext.Context.IsImported(import, curLine)) - return true; - } - catch (Exception) + var ctx = ASContext.Context; + if (!ctx.Settings.GenerateImports) return false; + if (ctx.CodeComplete.IsMetadataArgument(sci, position)) return false; + var importName = import.Name; + var curLine = sci.LineFromPosition(position); + if (ctx.IsImported(import, curLine)) { - return false; + var importType = import.Type; + var imports = ctx.ResolveImports(cFile); + return !imports.Any(it => it.Name == importName && it.Type != importType); } - - // class with same name exists in current package? - if (ASContext.Context.Features.hasPackages && import is ClassModel) + // insert import + sci.BeginUndoAction(); + try { - string cname = import.Name; - if (cFile.Package.Length > 0) cname = cFile.Package + "." + cname; - ClassModel inPackage = ASContext.Context.ResolveType(cname, cFile); - if (!inPackage.IsVoid()) - return true; + var imports = ctx.ResolveImports(cFile); + offset = ASGenerator.InsertImport(import, true); + if (imports.Any(it => it.Name == importName)) return false; } - - // insert import - if (ASContext.Context.Settings.GenerateImports) + finally { - sci.BeginUndoAction(); - try - { - offset = ASGenerator.InsertImport(import, true); - } - finally - { - sci.EndUndoAction(); - } - return true; + sci.EndUndoAction(); } - return false; + return true; } - private static string checkShortName(string name) + static string CheckShortName(string name) { int p = name.IndexOf('<'); if (p > 1 && name[p - 1] == '.') p--; return (p > 0) ? name.Substring(0, p) : name; } - private static void DispatchInsertedElement(ASResult context, char trigger) + static void DispatchInsertedElement(ASResult context, char trigger) { - Hashtable info = new Hashtable(); - info["context"] = context; - info["trigger"] = trigger; - DataEvent de = new DataEvent(EventType.Command, "ASCompletion.InsertedElement", info); + var info = new Hashtable {["context"] = context, ["trigger"] = trigger}; + var de = new DataEvent(EventType.Command, "ASCompletion.InsertedElement", info); EventManager.DispatchEvent(ASContext.Context, de); } - private static void InsertSnippet(string word) + static void InsertSnippet(string word) { - if (HasSnippet(word)) - PluginBase.MainForm.CallCommand("InsertSnippet", word); + if (HasSnippet(word)) PluginBase.MainForm.CallCommand("InsertSnippet", word); } public static bool HasSnippet(string word) { - String global = Path.Combine(PathHelper.SnippetDir, word + ".fds"); - String specificDir = Path.Combine(PathHelper.SnippetDir, ASContext.Context.Settings.LanguageId); - String specific = Path.Combine(specificDir, word + ".fds"); - return File.Exists(specific) || File.Exists(global); + return File.Exists(Path.Combine(PathHelper.SnippetDir, ASContext.Context.Settings.LanguageId, word + ".fds")) + || File.Exists(Path.Combine(PathHelper.SnippetDir, word + ".fds")); } /// @@ -4921,14 +5137,11 @@ public static bool HasSnippet(string word) /// Code was generated static bool CodeAutoOnChar(ScintillaControl sci, int value) { - if (ASContext.Context.Settings == null || !ASContext.Context.Settings.GenerateImports) - return false; - - int position = sci.CurrentPos; - - if (value == '*' && position > 1 && sci.CharAt(position - 2) == '.' && LastExpression != null) - return HandleWildcardList(sci, position, LastExpression); - + if (ASContext.Context.Settings is null + || !ASContext.Context.Settings.GenerateImports + || value != '*') return false; + var position = sci.CurrentPos; + if (position > 1 && sci.CharAt(position - 2) == '.' && LastExpression != null) return HandleWildcardList(sci, position, LastExpression); return false; } @@ -4947,21 +5160,17 @@ static bool HandleWildcardList(ScintillaControl sci, int position, ASExpr expr) var cFile = context.CurrentModel; var cClass = context.CurrentClass; var resolved = EvalExpression(expr.Value, expr, cFile, cClass, true, false); - if (resolved.IsNull() || !resolved.IsPackage || resolved.InFile == null) - return false; - - string package = resolved.InFile.Package; - string check = Regex.Replace(expr.Value, "\\s", "").TrimEnd('.'); - if (check != package) - return false; - + if (resolved.IsNull() || !resolved.IsPackage || resolved.InFile is null) return false; + var package = resolved.InFile.Package; + var check = Regex.Replace(expr.Value, "\\s", "").TrimEnd('.'); + if (check != package) return false; sci.BeginUndoAction(); try { // remove temp wildcard int startPos = expr.PositionExpression; sci.SetSel(startPos, position); - sci.ReplaceSel(""); + sci.ReplaceSel(string.Empty); // generate import if (context.Settings.GenerateImports) @@ -4980,16 +5189,17 @@ static bool HandleWildcardList(ScintillaControl sci, int position, ASExpr expr) } // show types - var list = new List(); var imports = context.ResolvePackage(package, false).Imports; - foreach (MemberModel import in imports) - list.Add(new MemberItem(import)); + var list = imports.Select(static it => new MemberItem(it)).ToArray(); CompletionList.Show(list, false); return true; } #endregion - + + public virtual string ToFunctionDeclarationString(MemberModel member) => member != null + ? $"Function/*({member.ParametersString()}):{member.Type}*/" + : "Function"; } #region completion list @@ -4998,110 +5208,66 @@ static bool HandleWildcardList(ScintillaControl sci, int position, ASExpr expr) /// public class MemberItem : ICompletionListItem { - protected MemberModel member; - private int icon; + public MemberModel Member { get; } + readonly int icon; public MemberItem(MemberModel oMember) { - member = oMember; - icon = PluginUI.GetIcon(member.Flags, member.Access); + Member = oMember; + icon = PluginUI.GetIcon(Member.Flags, Member.Access); } - public string Label - { - get { return member.FullName; } - } + public string Label => Member.FullName; - public virtual string Description - { - get - { - return ClassModel.MemberDeclaration(member) + ASDocumentation.GetTipDetails(member, null); - } - } + public virtual string Description => ClassModel.MemberDeclaration(Member) + ASDocumentation.GetTipDetails(Member, null); - public Bitmap Icon - { - get { return (Bitmap)ASContext.Panel.GetIcon(icon); } - } + public Bitmap Icon => (Bitmap)ASContext.Panel.GetIcon(icon); public string Value { get { - if (member.Name.IndexOf('<') > 0 && member.Template != null) - { - if (member.Name.IndexOfOrdinal(".<") > 0) - return member.Name.Substring(0, member.Name.IndexOfOrdinal(".<")); - - return member.Name.Substring(0, member.Name.IndexOf('<')); - } - return member.Name; + if (!Member.Name.Contains('<', out var p1) && p1 <= 0 || Member.Template is null) return Member.Name; + + // ActionScript3: Vector. + if (Member.Name.Contains(".<", out var p2) && p2 > 0) + return Member.Name.Substring(0, p2); + return Member.Name.Substring(0, p1); } } - public override string ToString() - { - return Label; - } + public override string ToString() => Label; } - /// - /// Nonexistent member completion list item - /// + /// + /// Nonexistent member completion list item + /// public class NonexistentMemberItem : ICompletionListItem { - private static Bitmap icon; - - private string memberName; - - public NonexistentMemberItem(string memberName) - { - this.memberName = memberName; - } - - public string Label - { - get { return memberName; } - } - - public virtual string Description - { - get - { - return memberName; - } - } - - public Bitmap Icon + static Bitmap icon; + + public NonexistentMemberItem(string memberName) => Label = memberName; + + public string Label { get; } + + public virtual string Description => Label; + + public Bitmap Icon => icon ??= (Bitmap) PluginBase.MainForm.FindImage("197"); + + public string Value { get { - if (icon == null) icon = (Bitmap)PluginBase.MainForm.FindImage("197"); - return icon; - } - } - - public string Value - { - get - { - if (memberName.IndexOf('<') > 0) - { - if (memberName.IndexOfOrdinal(".<") > 0) - return memberName.Substring(0, memberName.IndexOfOrdinal(".<")); - else return memberName.Substring(0, memberName.IndexOf('<')); - } - return memberName; - } - } - - public override string ToString() - { - return Label; - } - } - + if (!Label.Contains('<', out var p1)) return Label; + return Label.Contains(".<", out var p2) && p2 > 0 + ? Label.Substring(0, p2) + : Label.Substring(0, p1); + } + } + + public override string ToString() => Label; + } + /// /// Template completion list item /// @@ -5109,12 +5275,12 @@ public class TemplateItem : MemberItem { public TemplateItem(MemberModel oMember) : base(oMember) { } - override public string Description + public override string Description { get { - if (ASComplete.HasSnippet(member.Name)) - member.Comments = "[i](" + TextHelper.GetString("Info.InsertKeywordSnippet") + ")[/i]"; + if (ASComplete.HasSnippet(Member.Name)) + Member.Comments = "[i](" + TextHelper.GetString("Info.InsertKeywordSnippet") + ")[/i]"; return base.Description; } } @@ -5125,31 +5291,15 @@ override public string Description /// public class DeclarationItem : ICompletionListItem { - private string label; + public DeclarationItem(string label) => Label = label; - public DeclarationItem(string label) - { - this.label = label; - } + public string Label { get; } - public string Label - { - get { return label; } - } - public string Description - { - get { return TextHelper.GetString("Info.DeclarationTemplate"); } - } + public string Description => TextHelper.GetString("Info.DeclarationTemplate"); - public Bitmap Icon - { - get { return (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_DECLARATION); } - } + public Bitmap Icon => (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_DECLARATION); - public string Value - { - get { return label; } - } + public string Value => Label; } /// @@ -5157,59 +5307,46 @@ public string Value /// public class EventItem : ICompletionListItem { - private string name; - private string comments; - private CommentBlock cb; - public ClassModel EventType; + readonly string comments; + public readonly ClassModel EventType; + CommentBlock cb; public EventItem(string name, ClassModel type, string comments) { - this.name = name; + Label = name; EventType = type; this.comments = comments; } - public string Label - { - get { return name; } - } + public string Label { get; } + public string Description { get { if (!ASContext.CommonSettings.SmartTipsEnabled) return TextHelper.GetString("Info.EventConstant"); - if (cb == null) cb = ASDocumentation.ParseComment(comments ?? name); - string tip = (UITools.Manager.ShowDetails) ? ASDocumentation.GetTipFullDetails(cb, null) : ASDocumentation.GetTipShortDetails(cb, null); + cb ??= ASDocumentation.ParseComment(comments ?? Label); + var tip = UITools.Manager.ShowDetails + ? ASDocumentation.GetTipFullDetails(cb, null) + : ASDocumentation.GetTipShortDetails(cb, null); // remove paragraphs from comments return ASDocumentation.RemoveHTMLTags(tip).Trim(); } } - public Bitmap Icon - { - get { return (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_CONST); } - } + public Bitmap Icon => (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_CONST); - public string Value - { - get { return name; } - } + public string Value => Label; } public class CompletionItemComparer : IComparer { - public int Compare(ICompletionListItem a, ICompletionListItem b) - { - return a.Label.CompareTo(b.Label); - } - } - - public class CompletionItemCaseSensitiveImportComparer : IComparer - { - public int Compare(ICompletionListItem x, ICompletionListItem y) - { - return CaseSensitiveImportComparer.CompareImports(x.Label, y.Label); - } + public int Compare(ICompletionListItem a, ICompletionListItem b) => a.Label.CompareTo(b.Label); + } + + public class CompletionItemCaseSensitiveImportComparer : IComparer + { + public int Compare(ICompletionListItem x, ICompletionListItem y) => CaseSensitiveImportComparer.CompareImports(x.Label, y.Label); } #endregion @@ -5231,17 +5368,25 @@ public enum ComaExpression /// public sealed class ASExpr { + /// + /// End position of expression + /// public int Position; + + /// + /// Start position of expression + /// + public int PositionExpression; + public MemberModel ContextMember; public MemberList LocalVars; public MemberModel ContextFunction; public string FunctionBody; public int FunctionOffset; public bool BeforeBody; - - public int PositionExpression; public string Value; public List SubExpressions; + public List SubExpressionPositions; public string Separator; public int SeparatorPosition; public string WordBefore; @@ -5249,6 +5394,9 @@ public sealed class ASExpr public ComaExpression coma; public string RightOperator = string.Empty; + internal int LineFrom; + internal int LineTo; + public ASExpr() { } public ASExpr(ASExpr inContext) @@ -5263,7 +5411,7 @@ public ASExpr(ASExpr inContext) /// /// Expressions/tokens evaluation result /// - sealed public class ASResult + public sealed class ASResult { public ClassModel Type; public ClassModel InClass; @@ -5273,18 +5421,15 @@ sealed public class ASResult public bool IsStatic; public bool IsPackage; public ASExpr Context; - public String Path; + public string Path; - public bool IsNull() - { - return (Type == null && Member == null && !IsPackage); - } + public bool IsNull() => Type is null && Member is null && !IsPackage; } public sealed class ResolvedContext { + public readonly Hashtable Arguments = new Hashtable(); public int Position = -1; - public Hashtable Arguments = new Hashtable(); public ASResult Result; public ClassModel TokenType; } diff --git a/External/Plugins/ASCompletion/Completion/ASDocumentation.cs b/External/Plugins/ASCompletion/Completion/ASDocumentation.cs index 1be7ef0b3b..bf34a0e8e1 100644 --- a/External/Plugins/ASCompletion/Completion/ASDocumentation.cs +++ b/External/Plugins/ASCompletion/Completion/ASDocumentation.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Text.RegularExpressions; @@ -20,48 +19,45 @@ public class CommentBlock public string InfoTip; public string Return; public bool IsFunctionWithArguments; - public ArrayList ParamName; // TODO: change ArrayList for List - public ArrayList ParamDesc; - public ArrayList TagName; - public ArrayList TagDesc; + public List ParamName; + public List ParamDesc; + public List TagName; + public List TagDesc; } public class ASDocumentation { - static private List docVariables; + static List docVariables; #region regular_expressions - static private Regex re_tags = new Regex("<[/]?(p|br)[/]?>", RegexOptions.IgnoreCase | RegexOptions.Compiled); + + static readonly Regex re_tags = new Regex("<[/]?(p|br)[/]?>", RegexOptions.IgnoreCase | RegexOptions.Compiled); #endregion #region Comment generation - static public bool OnChar(ScintillaControl Sci, int Value, int position, int style) + public static bool OnChar(ScintillaControl sci, int value, int position, int style) { - if (style == 3 || style == 124) + if (style != 3 && style != 124) return false; + return value switch { - switch (Value) - { - // documentation tag - case '@': return HandleDocTagCompletion(Sci); - - // documentation bloc - case '*': return ASContext.Context.DocumentationGenerator.ContextualGenerator(Sci, position, new List()); - } - } - return false; + // documentation tag + '@' => HandleDocTagCompletion(sci), + // documentation bloc + '*' => ASContext.Context.DocumentationGenerator.ContextualGenerator(sci, position, new List()), + _ => false, + }; } - static private bool HandleDocTagCompletion(ScintillaControl Sci) + static bool HandleDocTagCompletion(ScintillaControl sci) { - if (ASContext.CommonSettings.JavadocTags == null || ASContext.CommonSettings.JavadocTags.Length == 0) - return false; + if (ASContext.CommonSettings.JavadocTags.IsNullOrEmpty()) return false; - string txt = Sci.GetLine(Sci.CurrentLine).TrimStart(); + string txt = sci.GetLine(sci.CurrentLine).TrimStart(); if (!Regex.IsMatch(txt, "^\\*[\\s]*\\@")) return false; // build tag list - if (docVariables == null) + if (docVariables is null) { docVariables = new List(); foreach (string tag in ASContext.CommonSettings.JavadocTags) @@ -78,42 +74,33 @@ static private bool HandleDocTagCompletion(ScintillaControl Sci) /// /// Documentation tag template completion list item /// - private class TagItem : ICompletionListItem + class TagItem : ICompletionListItem { - private string label; - public TagItem(string label) { - this.label = label; - } - - public string Label { - get { return label; } - } - public string Description { - get { return TextHelper.GetString("Label.DocTagTemplate"); } - } - - public Bitmap Icon { - get { return (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_DECLARATION); } - } - - public string Value { - get { return label; } + Label = label; } + + public string Label { get; } + + public string Description => TextHelper.GetString("Label.DocTagTemplate"); + + public Bitmap Icon => (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_DECLARATION); + + public string Value => Label; } #endregion #region Tooltips - static private Regex reNewLine = new Regex("[\r\n]+", RegexOptions.Compiled); - static private Regex reKeepTags = new Regex("<([/]?(b|i|s|u))>", RegexOptions.IgnoreCase | RegexOptions.Compiled); - static private Regex reSpecialTags = new Regex("<([/]?)(code|small|strong|em)>", RegexOptions.IgnoreCase | RegexOptions.Compiled); - static private Regex reStripTags = new Regex("<[/]?[a-z]+[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled); - static private Regex reDocTags = new Regex("\n@(?[a-z]+)\\s", RegexOptions.IgnoreCase | RegexOptions.Compiled); - static private Regex reSplitParams = new Regex("(?[\\w$]+)\\s", RegexOptions.Compiled); + static readonly Regex reNewLine = new Regex("[\r\n]+", RegexOptions.Compiled); + static readonly Regex reKeepTags = new Regex("<([/]?(b|i|s|u))>", RegexOptions.IgnoreCase | RegexOptions.Compiled); + static readonly Regex reSpecialTags = new Regex("<([/]?)(code|small|strong|em)>", RegexOptions.IgnoreCase | RegexOptions.Compiled); + static readonly Regex reStripTags = new Regex("<[/]?[a-z]+[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled); + static readonly Regex reDocTags = new Regex("\n@(?[a-z]+)\\s", RegexOptions.IgnoreCase | RegexOptions.Compiled); + static readonly Regex reSplitParams = new Regex("(?[\\w$]+)\\s", RegexOptions.Compiled); - static public CommentBlock ParseComment(string comment) + public static CommentBlock ParseComment(string comment) { // cleanup comment = comment.Replace("<", "<").Replace(">", ">").Replace(" ", " "); @@ -122,25 +109,29 @@ static public CommentBlock ParseComment(string comment) { string tag = match.Groups[2].Value; bool open = match.Groups[1].Length == 0; - switch (tag) + return tag switch { - case "small": return open ? "[size=-2]" : "[/size]"; - case "code": return open ? "[font=Courier New]" : "[/font]"; - case "strong": return open ? "[b]" : "[/b]"; - case "em": return open ? "[i]" : "[/i]"; - } - return ""; + "small" => open ? "[size=-2]" : "[/size]", + "code" => open ? "[font=Courier New]" : "[/font]", + "strong" => open ? "[b]" : "[/b]", + "em" => open ? "[i]" : "[/i]", + _ => "", + }; }); comment = reStripTags.Replace(comment, ""); string[] lines = reNewLine.Split(comment); - char[] trim = new char[] { ' ', '\t', '*' }; + char[] trim = { ' ', '\t', '*' }; bool addNL = false; comment = ""; foreach (string line in lines) { string temp = line.Trim(trim); if (addNL) comment += '\n' + temp; - else { comment += temp; addNL = true; } + else + { + comment += temp; + addNL = true; + } } // extraction CommentBlock cb = new CommentBlock(); @@ -152,15 +143,15 @@ static public CommentBlock ParseComment(string comment) return cb; } - if (tags[0].Index > 0) cb.Description = comment.Substring(0, tags[0].Index).Trim(); - else cb.Description = ""; - cb.TagName = new ArrayList(); - cb.TagDesc = new ArrayList(); - - Group gTag; - for(int i=0; i 0 + ? comment.Substring(0, tags[0].Index).Trim() + : string.Empty; + cb.TagName = new List(); + cb.TagDesc = new List(); + + for(int i = 0; i < tags.Count; i++) { - gTag = tags[i].Groups["tag"]; + var gTag = tags[i].Groups["tag"]; string tag = gTag.Value; int start = gTag.Index+gTag.Length; int end = (i(); + cb.ParamDesc = new List(); } cb.ParamName.Add(mVar.Value); cb.ParamDesc.Add(desc.Substring(mVar.Index + mVar.Length).TrimStart()); @@ -195,7 +187,7 @@ static public CommentBlock ParseComment(string comment) } - static public string GetTipDetails(MemberModel member, string highlightParam) + public static string GetTipDetails(MemberModel member, string highlightParam) { try { @@ -210,21 +202,18 @@ static public string GetTipDetails(MemberModel member, string highlightParam) } } - static public string RemoveHTMLTags(string tip) - { - return re_tags.Replace(tip, ""); - } - + public static string RemoveHTMLTags(string tip) => re_tags.Replace(tip, ""); + /// /// Short contextual details to display in tips /// /// Member data /// Parameter to detail /// - static public string GetTipShortDetails(MemberModel member, string highlightParam) + public static string GetTipShortDetails(MemberModel member, string highlightParam) { - if (member == null || member.Comments == null || !ASContext.CommonSettings.SmartTipsEnabled) return ""; - CommentBlock cb = ParseComment(member.Comments); + if (member?.Comments is null || !ASContext.CommonSettings.SmartTipsEnabled) return ""; + var cb = ParseComment(member.Comments); cb.IsFunctionWithArguments = IsFunctionWithArguments(member); return " \u2026" + GetTipShortDetails(cb, highlightParam); } @@ -232,7 +221,7 @@ static public string GetTipShortDetails(MemberModel member, string highlightPara static bool IsFunctionWithArguments(MemberModel member) { return member != null && (member.Flags & FlagType.Function) > 0 - && member.Parameters != null && member.Parameters.Count > 0; + && !member.Parameters.IsNullOrEmpty(); } /// @@ -240,7 +229,7 @@ static bool IsFunctionWithArguments(MemberModel member) /// /// Parsed comments /// Formated comments - static public string GetTipShortDetails(CommentBlock cb, string highlightParam) + public static string GetTipShortDetails(CommentBlock cb, string highlightParam) { string details = ""; @@ -249,10 +238,10 @@ static public string GetTipShortDetails(CommentBlock cb, string highlightParam) { for(int i=0; i /// Split multiline text and return 2 lines or less of text /// - static public string Get2LinesOf(string text) - { - return Get2LinesOf(text, false); - } + public static string Get2LinesOf(string text) => Get2LinesOf(text, false); - static public string Get2LinesOf(string text, bool alwaysAddShortcutDocs) + public static string Get2LinesOf(string text, bool alwaysAddShortcutDocs) { string[] lines = text.Split('\n'); text = ""; @@ -299,11 +285,11 @@ static public string Get2LinesOf(string text, bool alwaysAddShortcutDocs) /// /// Member data /// Parameter to highlight - /// Formated comments - static public string GetTipFullDetails(MemberModel member, string highlightParam) + /// Formatted comments + public static string GetTipFullDetails(MemberModel member, string highlightParam) { - if (member == null || member.Comments == null || !ASContext.CommonSettings.SmartTipsEnabled) return ""; - CommentBlock cb = ParseComment(member.Comments); + if (member?.Comments is null || !ASContext.CommonSettings.SmartTipsEnabled) return ""; + var cb = ParseComment(member.Comments); cb.IsFunctionWithArguments = IsFunctionWithArguments(member); return GetTipFullDetails(cb, highlightParam); } @@ -313,14 +299,14 @@ static public string GetTipFullDetails(MemberModel member, string highlightParam /// /// Parsed comments /// Formated comments - static public string GetTipFullDetails(CommentBlock cb, string highlightParam) + public static string GetTipFullDetails(CommentBlock cb, string highlightParam) { string details = ""; if (cb.Description.Length > 0) { string[] lines = cb.Description.Split('\n'); int n = Math.Min(lines.Length, ASContext.CommonSettings.DescriptionLinesLimit); - for(int i=0; i ASContext.CommonSettings.DescriptionLinesLimit) details = details.TrimEnd() + " \u2026\n"; } @@ -329,40 +315,39 @@ static public string GetTipFullDetails(CommentBlock cb, string highlightParam) { bool hasUsage = false; for(int i=0; i 0) + if (!cb.ParamName.IsNullOrEmpty()) { details += "\nParam:"; for(int i=0; i ASContext.Context.CurrentModel.haXe; + public static bool HandleGeneratorCompletion(ScintillaControl sci, bool autoHide, string word) - { - var generator = ASContext.Context.CodeGenerator as ASGenerator; - if (generator == null) return false; - if (!string.IsNullOrEmpty(word) && word == ASContext.Context.Features.overrideKey) - return generator.HandleOverrideCompletion(autoHide); - return false; - } - + => !string.IsNullOrEmpty(word) + && word == ASContext.Context.Features.overrideKey + && ASContext.Context.CodeGenerator is ASGenerator generator + && generator.HandleOverrideCompletion(autoHide); + public static void ContextualGenerator(ScintillaControl sci, List options) - { - ASContext.Context.CodeGenerator.ContextualGenerator(sci, sci.CurrentPos, options); - } + => ASContext.Context.CodeGenerator.ContextualGenerator(sci, sci.CurrentPos, options); public bool ContextualGenerator(ScintillaControl sci, int position, List options) { - var context = ASContext.Context; - if (context is ASContext) ((ASContext)context).UpdateCurrentFile(false); // update model + if (sci.SelTextSize != 0) return false; + if (ASContext.Context is ASContext ctx) ctx.UpdateCurrentFile(false); lookupPosition = -1; - if (sci.PositionIsOnComment(position)) return false; - int style = sci.BaseStyleAt(position); + if (sci.PositionIsOnComment(position) + // for example: new NewClass$(EntryPoint)/*comment*/(); + && sci.PositionIsOnComment(--position)) return false; + var style = sci.BaseStyleAt(position); if (style == 19 || style == 24) // on keyword return false; contextMatch = null; contextToken = sci.GetWordFromPosition(position); var expr = ASComplete.GetExpressionType(sci, sci.WordEndPosition(position, true)); + contextResolved = expr; ContextualGenerator(sci, position, expr, options); return true; } protected virtual void ContextualGenerator(ScintillaControl sci, int position, ASResult resolve, List options) { + var suggestItemDeclaration = false; + var ctx = ASContext.Context; var line = sci.LineFromPosition(position); var found = GetDeclarationAtLine(line); + if (contextToken is not null && resolve.Member is null && sci.BaseStyleAt(position) != 5) + { + // import declaration + if ((resolve.Type is null || resolve.Type.IsVoid() || !ctx.IsImported(resolve.Type, line)) && CheckAutoImport(resolve, options)) return; + if (resolve.Type is null) + { + if (TryShowGenerateType(sci, position, resolve, found, options)) return; + suggestItemDeclaration = ASComplete.IsTextStyle(sci.BaseStyleAt(position - 1)); + } + } + + var behavior = GetCodeGeneratorBehavior(); + if (behavior is not null && behavior.ContextualGenerator(sci, position, resolve, options)) return; + if (CanShowConvertToConst(sci, position, resolve, found)) { ShowConvertToConst(found, options); return; } - contextResolved = resolve; - var context = ASContext.Context; - var isNotInterface = (context.CurrentClass.Flags & FlagType.Interface) == 0; - // ignore automatic vars (MovieClip members) - if (isNotInterface - && resolve.Member != null - && (((resolve.Member.Flags & FlagType.AutomaticVar) > 0) || (resolve.InClass != null && resolve.InClass.QualifiedName == "Object"))) + if (resolve.Member is not null && ((resolve.Member.Flags & FlagType.AutomaticVar) > 0 || resolve.InClass?.QualifiedName == "Object")) { resolve.Member = null; resolve.Type = null; } - if (isNotInterface && !found.InClass.IsVoid() && contextToken != null) + if (!found.InClass.IsVoid() && contextToken is not null) { // implement interface if (CanShowImplementInterfaceList(sci, position, resolve, found)) { - contextParam = resolve.Type.Type; + if (ctx.Features.hasGenerics && resolve.RelClass?.Implements is not null) + { + var name = resolve.Type.Name; + foreach (var it in resolve.RelClass.Implements) + { + string interfaceName; + if (it.IndexOf('<') is { } p && p != -1) interfaceName = it.Substring(0, p); + else interfaceName = it; + if (interfaceName != name) continue; + contextParam = it; + break; + } + } + else contextParam = resolve.Type.Type; ShowImplementInterface(found, options); return; } // promote to class var - if (!context.CurrentClass.IsVoid() && resolve.Member != null && (resolve.Member.Flags & FlagType.LocalVar) > 0) + if (!ctx.CurrentClass.IsVoid() && resolve.Member is not null && (resolve.Member.Flags & FlagType.LocalVar) > 0) { contextMember = resolve.Member; ShowPromoteLocalAndAddParameter(found, options); return; } } - - var suggestItemDeclaration = false; - if (contextToken != null && resolve.Member == null && sci.BaseStyleAt(position) != 5) - { - // import declaration - if ((resolve.Type == null || resolve.Type.IsVoid() || !context.IsImported(resolve.Type, line)) && CheckAutoImport(resolve, options)) return; - if (resolve.Type == null) - { - suggestItemDeclaration = ASComplete.IsTextStyle(sci.BaseStyleAt(position - 1)); - } - } - if (isNotInterface && found.Member != null) + + if (found.Member is not null) { // private var -> property if ((found.Member.Flags & FlagType.Variable) > 0 && (found.Member.Flags & FlagType.LocalVar) == 0) { var text = sci.GetLine(line); // maybe we just want to import the member's non-imported type - Match m = Regex.Match(text, String.Format(patternVarDecl, found.Member.Name, contextToken)); + var m = Regex.Match(text, string.Format(patternVarDecl, found.Member.Name, contextToken)); if (m.Success) { contextMatch = m; - ClassModel type = context.ResolveType(contextToken, context.CurrentModel); - if (type.IsVoid() && CheckAutoImport(resolve, options)) - return; + var type = ctx.ResolveType(contextToken, ctx.CurrentModel); + if (type.IsVoid() && CheckAutoImport(resolve, options)) return; } - ShowGetSetList(found, options); + if (CanShowGetSetList(sci, position, resolve, found)) ShowGetSetList(found, options); return; } // inside a function if ((found.Member.Flags & (FlagType.Function | FlagType.Getter | FlagType.Setter)) > 0 - && resolve.Member == null && resolve.Type == null) + && resolve.Member is null && resolve.Type is null) { - if (IsHaxe) + if (CanShowGenerateGetter(sci, position, resolve, found)) { - if (contextToken == "get") - { - ShowGetterList(found, options); - return; - } - if (contextToken == "set") - { - ShowSetterList(found, options); - return; - } + ShowGetterList(found, options); + return; + } + if (CanShowGenerateSetter(sci, position, resolve, found)) + { + ShowSetterList(found, options); + return; } var text = sci.GetLine(line); - if (contextToken != null) + if (contextToken is not null) { // "generate event handlers" suggestion - string re = String.Format(patternEvent, contextToken); - Match m = Regex.Match(text, re, RegexOptions.IgnoreCase); + var re = string.Format(patternEvent, contextToken); + var m = Regex.Match(text, re, RegexOptions.IgnoreCase); if (m.Success) { contextMatch = m; - contextParam = CheckEventType(m.Groups["event"].Value); + var pos = ASComplete.ExpressionEndPosition(sci, sci.PositionFromLine(line) + m.Index); + var expr = ASComplete.GetExpressionType(sci, pos, false, true); + contextParam = ((ASGenerator) ctx.CodeGenerator).CheckEventType(expr.Member, m.Groups["event"].Value); ShowEventList(found, options); return; } - m = Regex.Match(text, String.Format(patternAS2Delegate, contextToken), RegexOptions.IgnoreCase); + m = Regex.Match(text, string.Format(patternAS2Delegate, contextToken), RegexOptions.IgnoreCase); if (m.Success) { contextMatch = m; @@ -187,7 +199,7 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A return; } // suggest delegate - if (context.Features.hasDelegates) + if (ctx.Features.hasDelegates) { m = Regex.Match(text, @"([a-z0-9_.]+)\s*\+=\s*" + contextToken, RegexOptions.IgnoreCase); if (m.Success) @@ -195,7 +207,7 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A int offset = sci.PositionFromLine(sci.LineFromPosition(position)) + m.Groups[1].Index + m.Groups[1].Length; resolve = ASComplete.GetExpressionType(sci, offset); - if (resolve.Member != null) + if (resolve.Member is not null) contextMember = ResolveDelegate(resolve.Member.Type, resolve.InFile); contextMatch = m; ShowDelegateList(found, options); @@ -206,13 +218,13 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A else { // insert a default handler name, then "generate event handlers" suggestion - Match m = Regex.Match(text, String.Format(patternEvent, ""), RegexOptions.IgnoreCase); + var m = Regex.Match(text, string.Format(patternEvent, ""), RegexOptions.IgnoreCase); if (m.Success) { int regexIndex = m.Index + sci.PositionFromLine(sci.CurrentLine); GenerateDefaultHandlerName(sci, position, regexIndex, m.Groups["event"].Value, true); resolve = ASComplete.GetExpressionType(sci, sci.CurrentPos); - if (resolve.Member == null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0) + if (resolve.Member is null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0) { contextMatch = m; contextParam = CheckEventType(m.Groups["event"].Value); @@ -222,7 +234,7 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A } // insert default delegate name, then "generate delegate" suggestion - if (context.Features.hasDelegates) + if (ctx.Features.hasDelegates) { m = Regex.Match(text, @"([a-z0-9_.]+)\s*\+=\s*", RegexOptions.IgnoreCase); if (m.Success) @@ -230,14 +242,14 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A int offset = sci.PositionFromLine(sci.LineFromPosition(position)) + m.Groups[1].Index + m.Groups[1].Length; resolve = ASComplete.GetExpressionType(sci, offset); - if (resolve.Member != null) + if (resolve.Member is not null) { contextMember = ResolveDelegate(resolve.Member.Type, resolve.InFile); - string delegateName = resolve.Member.Name; + var delegateName = resolve.Member.Name; if (delegateName.StartsWithOrdinal("on")) delegateName = delegateName.Substring(2); GenerateDefaultHandlerName(sci, position, offset, delegateName, false); resolve = ASComplete.GetExpressionType(sci, sci.CurrentPos); - if (resolve.Member == null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0) + if (resolve.Member is null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0) { contextMatch = m; ShowDelegateList(found, options); @@ -251,8 +263,8 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A // "Generate fields from parameters" suggestion if ((found.Member.Flags & FlagType.Function) > 0 - && found.Member.Parameters != null && (found.Member.Parameters.Count > 0) - && resolve.Member != null && (resolve.Member.Flags & FlagType.ParameterVar) > 0) + && !found.Member.Parameters.IsNullOrEmpty() + && resolve.Member is not null && (resolve.Member.Flags & FlagType.ParameterVar) > 0) { contextMember = resolve.Member; ShowFieldFromParameter(found, options); @@ -262,43 +274,32 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A // "add to interface" suggestion if (CanShowAddToInterfaceList(sci, position, resolve, found)) { - string funcName = found.Member.Name; - FlagType flags = found.Member.Flags & ~FlagType.Access; - - List interfaces = new List(); - foreach (string interf in found.InClass.Implements) + var name = found.Member.Name; + var flags = found.Member.Flags & ~FlagType.Access; + var list = new List(); + foreach (var it in found.InClass.Implements) { - bool skip = false; - ClassModel cm = context.ResolveType(interf, context.CurrentModel); - foreach (MemberModel m in cm.Members) - { - if (m.Name.Equals(funcName) && m.Flags.Equals(flags)) - { - skip = true; - break; - } - } - if (!skip) - { - interfaces.Add(interf); - } + var cm = ctx.ResolveType(it, ctx.CurrentModel); + if (!cm.ContainsMember(name, flags, false)) list.Add(it); } - if (interfaces.Count > 0) + if (list.Count > 0) { - ShowAddInterfaceDefList(found, interfaces, options); + ShowAddInterfaceDefList(found, list, options); return; } } // "assign var to statement" suggestion - int curLine = sci.CurrentLine; - string ln = sci.GetLine(curLine).TrimEnd(); - if (ln.Length > 0 && !ln.Contains('=') - && ln.Length <= sci.CurrentPos - sci.PositionFromLine(curLine)) // cursor at end of line + var curLine = sci.GetLine(sci.CurrentLine); + var ln = curLine.TrimEnd(); + if (ln.Length > 0 + && sci.PositionFromLine(sci.CurrentLine) is var positionFromLine + && ln.Length <= sci.CurrentPos - positionFromLine) // cursor at end of line { - var returnType = GetStatementReturnType(sci, found.InClass, sci.GetLine(curLine), sci.PositionFromLine(curLine)); - if (returnType.resolve.Member?.Type == ASContext.Context.Features.voidKey) return; - if (returnType.resolve.Type == null && returnType.resolve.Context?.WordBefore == "new") ShowNewClassList(found, returnType.resolve.Context, options); + var returnType = GetStatementReturnType(sci, found.InClass, curLine, positionFromLine); + if (!CanShowAssignStatementToVariable(sci, returnType.Resolve)) return; + if (CanShowGenerateClass(sci, position, resolve, found)) ShowGenerateClassList(found, returnType.Resolve.Context, options); + else if (returnType.Resolve.Type is null && returnType.Resolve.Member is null) return; else ShowAssignStatementToVarList(found, returnType, options); return; } @@ -309,7 +310,7 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A { bool hasConstructor = false; bool hasToString = false; - foreach (MemberModel m in context.CurrentClass.Members) + foreach (MemberModel m in ctx.CurrentClass.Members) { if (!hasConstructor && (m.Flags & FlagType.Constructor) > 0) hasConstructor = true; @@ -325,23 +326,22 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A } } - if (isNotInterface - && resolve.Member != null - && resolve.Type != null - && resolve.Type.QualifiedName == context.Features.stringKey + if (resolve.Member is not null + && resolve.Type is not null + && resolve.Type.QualifiedName == ctx.Features.stringKey && !found.InClass.IsVoid()) { int lineStartPos = sci.PositionFromLine(sci.CurrentLine); var text = sci.GetLine(line); - string lineStart = text.Substring(0, sci.CurrentPos - lineStartPos); - Match m = Regex.Match(lineStart, String.Format(@"new\s+(?\w+)\s*\(\s*\w+", lineStart)); + var lineStart = text.Substring(0, sci.CurrentPos - lineStartPos); + var m = Regex.Match(lineStart, @"new\s+(?\w+)\s*\(\s*\w+"); if (m.Success) { - Group g = m.Groups["event"]; - ASResult eventResolve = ASComplete.GetExpressionType(sci, lineStartPos + g.Index + g.Length); - if (eventResolve != null && eventResolve.Type != null) + var g = m.Groups["event"]; + var eventResolve = ASComplete.GetExpressionType(sci, lineStartPos + g.Index + g.Length); + if (eventResolve?.Type is not null) { - ClassModel aType = eventResolve.Type; + var aType = eventResolve.Type; aType.ResolveExtends(); while (!aType.IsVoid() && aType.QualifiedName != "Object") { @@ -358,88 +358,96 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A } // suggest declaration - if (contextToken != null) + if (contextToken is not null) { if (suggestItemDeclaration) { var text = sci.GetLine(line); - Match m = Regex.Match(text, String.Format(patternClass, contextToken)); - if (m.Success) + Match m; + if (CanShowGenerateClass(sci, position, resolve, found) + && (m = Regex.Match(text, string.Format(patternClass, contextToken))).Success) { contextMatch = m; - ShowNewClassList(found, options); + ShowGenerateClassList(found, options); } else if (!found.InClass.IsVoid()) { - m = Regex.Match(text, String.Format(patternMethod, contextToken)); + m = Regex.Match(text, string.Format(patternMethod, contextToken)); if (m.Success) { - contextMatch = m; - ShowNewMethodList(found, options); + if (CanShowNewMethodList(sci, position, resolve, found)) + { + contextMatch = m; + ((ASGenerator) ctx.CodeGenerator).ShowNewMethodList(sci, resolve, found, options); + } + } + else + { + if (CanShowNewVarList(sci, position, resolve, found)) ((ASGenerator) ctx.CodeGenerator).ShowNewVarList(sci, resolve, found, options); + if (CanShowGenerateInterface(sci, position, resolve, found)) ShowGenerateInterfaceList(resolve, found, options); } - else ShowNewVarList(found, options); } } - else + else if (resolve.Member is not null + && (resolve.Member.Flags & FlagType.Function) != 0 + && resolve.InClass?.InFile.FileName is {} classFileName + && File.Exists(classFileName) + && !classFileName.StartsWithOrdinal(PathHelper.AppDir)) { - if (resolve.InClass != null - && resolve.InClass.InFile != null - && resolve.Member != null - && (resolve.Member.Flags & FlagType.Function) > 0 - && File.Exists(resolve.InClass.InFile.FileName) - && !resolve.InClass.InFile.FileName.StartsWithOrdinal(PathHelper.AppDir)) + var text = sci.GetLine(line); + var m1 = Regex.Match(text, string.Format(patternMethodDecl, contextToken)); + if (!m1.Success && Regex.IsMatch(text, string.Format(patternMethod, contextToken))) { - var text = sci.GetLine(line); - Match m = Regex.Match(text, String.Format(patternMethodDecl, contextToken)); - Match m2 = Regex.Match(text, String.Format(patternMethod, contextToken)); - if (!m.Success && m2.Success) - { - contextMatch = m; - ShowChangeMethodDeclList(found, options); - } + contextMatch = m1; + ShowChangeMethodDeclList(found, options); } - else if (resolve.Type != null - && resolve.Type.InFile != null - && resolve.RelClass != null - && File.Exists(resolve.Type.InFile.FileName) - && !resolve.Type.InFile.FileName.StartsWithOrdinal(PathHelper.AppDir)) + } + else if (resolve.RelClass is not null + && resolve.Type?.InFile.FileName is {} typeFileName + && File.Exists(typeFileName) + && !typeFileName.StartsWithOrdinal(PathHelper.AppDir)) + { + var text = sci.GetLine(line); + var m = Regex.Match(text, string.Format(patternClass, contextToken)); + if (m.Success) { - var text = sci.GetLine(line); - var m = Regex.Match(text, string.Format(patternClass, contextToken)); - if (m.Success) + contextMatch = m; + var type = resolve.Type; + var constructor = type.SearchMember(FlagType.Constructor, true); + if (constructor is null) ShowConstructorAndToStringList(new FoundDeclaration {InClass = resolve.Type}, false, true, options); + else { - contextMatch = m; - MemberModel constructor = null; - var type = resolve.Type; - while (!type.IsVoid()) - { - constructor = type.Members.Search(type.Name, FlagType.Constructor, 0); - if (constructor != null) break; - type.ResolveExtends(); - type = type.Extends; - } - if (constructor == null) ShowConstructorAndToStringList(new FoundDeclaration { InClass = resolve.Type }, false, true, options); + var constructorParametersCount = constructor.Parameters?.Count ?? 0; + var wordEndPosition = sci.WordEndPosition(sci.CurrentPos, true); + var parameters = ParseFunctionParameters(sci, wordEndPosition); + if (parameters.Count != constructorParametersCount) ShowChangeConstructorDeclarationList(found, parameters, options); else { - var constructorParametersCount = constructor.Parameters?.Count ?? 0; - var wordEndPosition = sci.WordEndPosition(sci.CurrentPos, true); - var parameters = ParseFunctionParameters(sci, wordEndPosition); - if (parameters.Count != constructorParametersCount) ShowChangeConstructorDeclarationList(found, parameters, options); - else + for (var i = 0; i < parameters.Count; i++) { - for (var i = 0; i < parameters.Count; i++) - { - if (parameters[i].paramType == constructor.Parameters[i].Type) continue; - ShowChangeConstructorDeclarationList(found, parameters, options); - break; - } + if (parameters[i].paramType == constructor.Parameters[i].Type) continue; + ShowChangeConstructorDeclarationList(found, parameters, options); + break; } } } } } } - // TODO: Empty line, show generators list? yep + } + + /// + /// Check if "Assign statement to variable" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Expression at cursor position + /// true, if can show "Assign statement to variable" list + protected virtual bool CanShowAssignStatementToVariable(ScintillaControl sci, ASResult expr) + { + // for example: return expr + if (expr.Context.WordBefore == ASContext.Context.Features.ReturnKey) return false; + if (expr.Member is null) return expr.Type != ClassModel.VoidClass; + return expr.Member.Type is { } type && type != ASContext.Context.Features.voidKey; } /// @@ -449,13 +457,43 @@ protected virtual void ContextualGenerator(ScintillaControl sci, int position, A /// Cursor position /// Expression at cursor position /// The declaration target at current line(can not be null) - /// true, if can show `Convert to constant` list + /// true, if can show "Convert to constant" list protected virtual bool CanShowConvertToConst(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) { return !ASContext.Context.CurrentClass.Flags.HasFlag(FlagType.Interface) && ASComplete.IsLiteralStyle(sci.BaseStyleAt(position)); } + /// + /// Check if "Getter and Setter" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// The declaration target at current line(can not be null) + /// true, if can show "Getter and Setter" list + protected virtual bool CanShowGetSetList(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) => true; + + /// + /// Check if "Getter" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// The declaration target at current line(can not be null) + /// true, if can show "Getter" list + protected virtual bool CanShowGenerateGetter(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) => false; + + /// + /// Check if "Setter" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// The declaration target at current line(can not be null) + /// true, if can show "Setter" list + protected virtual bool CanShowGenerateSetter(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) => false; + /// /// Check if "Generate constructor" and "Generate toString()" are available at the current cursor position. /// @@ -463,14 +501,15 @@ protected virtual bool CanShowConvertToConst(ScintillaControl sci, int position, /// Cursor position /// Expression at cursor position /// The declaration target at current line(can not be null) - /// true, if can show `Generate constructor` and(or) `Generate toString()` list + /// true, if can show "Generate constructor" and(or) "Generate toString()" list protected virtual bool CanShowGenerateConstructorAndToString(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) { - return contextToken == null - && found.Member == null + return contextToken is null + && found.Member is null && !found.InClass.IsVoid() && !found.InClass.Flags.HasFlag(FlagType.Interface) - && position < sci.LineEndPosition(found.InClass.LineTo); + && position < sci.LineEndPosition(found.InClass.LineTo) + && !ASContext.Context.CodeComplete.PositionIsBeforeBody(sci, position, found.InClass); } /// @@ -480,11 +519,48 @@ protected virtual bool CanShowGenerateConstructorAndToString(ScintillaControl sc /// Cursor position /// Expression at cursor position /// Declaration target at current line(can not be null) - /// true, if can show `Implement Interface` list + /// true, if can show "Implement Interface" list protected virtual bool CanShowImplementInterfaceList(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) { - return expr.Context.ContextFunction == null && expr.Context.ContextMember == null - && expr.Member == null && expr.Type != null && (expr.Type.Flags & FlagType.Interface) > 0; + if (expr.Context.ContextFunction is not null || expr.Context.ContextMember is not null + || expr.Member is not null + || expr.Type is null || (expr.Type.Flags & FlagType.Interface) == 0) return false; + var type = expr.Type; + type.ResolveExtends(); + while (!type.IsVoid()) + { + if (type.Members.Count > 0) return true; + type = type.Extends; + } + return false; + } + + /// + /// Check if "Generate public function and Generate public callback" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// Declaration target at current line(can not be null) + /// true, if can show "Generate public function and Generate public callback" list + protected virtual bool CanShowNewMethodList(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) + { + var inClass = expr.RelClass ?? found.InClass; + return (inClass.Flags & FlagType.Interface) == 0 || !expr.IsStatic; + } + + /// + /// Check if "Generate public variable" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// Declaration target at current line(can not be null) + /// true, if can show "Generate public function and Generate public callback" list + protected virtual bool CanShowNewVarList(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) + { + var inClass = expr.RelClass ?? found.InClass; + return (inClass.Flags & FlagType.Interface) == 0 || !expr.IsStatic; } /// @@ -494,10 +570,10 @@ protected virtual bool CanShowImplementInterfaceList(ScintillaControl sci, int p /// Cursor position /// Expression at cursor position /// Declaration target at current line(can not be null) - /// true, if can show `Add to interface` list + /// true, if can show "Add to interface" list protected virtual bool CanShowAddToInterfaceList(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) { - return expr.Member != null + return expr.Member is not null && !expr.Member.Flags.HasFlag(FlagType.Static) && !expr.Member.Flags.HasFlag(FlagType.Constructor) && expr.Member.Name == found.Member.Name @@ -506,20 +582,83 @@ protected virtual bool CanShowAddToInterfaceList(ScintillaControl sci, int posit || (found.Member.Flags & FlagType.Getter) > 0 || (found.Member.Flags & FlagType.Setter) > 0) && !found.InClass.IsVoid() - && found.InClass.Implements != null + && found.InClass.Implements is not null && found.InClass.Implements.Count > 0; } - private static MemberModel ResolveDelegate(string type, FileModel inFile) + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// Declaration target at current line(can not be null) + /// + /// + protected virtual bool TryShowGenerateType(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found, List options) + { + var result = false; + if (CanShowGenerateClass(sci, position, expr, found)) + { + ShowGenerateClassList(found, expr.Context, options); + result = true; + } + if (CanShowGenerateInterface(sci, position, expr, found)) + { + ShowGenerateInterfaceList(expr, found, options); + result = true; + } + return result; + } + + /// + /// Check if "Create new class" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// Declaration target at current line(can not be null) + /// true, if can show "Create new class" list + protected virtual bool CanShowGenerateClass(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) + { + // for example: public var foo : Foo + return expr.Context.Separator == ":" + // for example, good: new Type(), bad: new Type().value + || (expr.Context.WordBefore == "new" && !expr.Context.Value.Contains("~.")) + // for example: class Foo extends Bar + || (expr.Context.WordBefore == ASContext.Context.Features.ExtendsKey + && ASContext.Context.CurrentClass.Flags is var flags + && flags.HasFlag(FlagType.Class) + // for example: interface Foo extends Bar + && !flags.HasFlag(FlagType.Interface) + && ASContext.Context.CodeComplete.PositionIsBeforeBody(sci, position, found.InClass)); + } + + /// + /// Check if "Create new interface" are available at the current cursor position. + /// + /// The Scintilla control containing the document + /// Cursor position + /// Expression at cursor position + /// Declaration target at current line(can not be null) + /// true, if can show "Create new interface" list + protected virtual bool CanShowGenerateInterface(ScintillaControl sci, int position, ASResult expr, FoundDeclaration found) + { + return contextToken is not null + && ASComplete.IsTextStyle(sci.BaseStyleAt(position - 1)) + // for example: implements IFoo + && (expr.Context.WordBefore == ASContext.Context.Features.ImplementsKey && ASContext.Context.CodeComplete.PositionIsBeforeBody(sci, position, found.InClass) + // for example: public var foo : Fo|o + || (expr.Context.Separator == ":")); + } + + static MemberModel ResolveDelegate(string type, FileModel inFile) { foreach (MemberModel def in inFile.Members) if (def.Name == type && (def.Flags & FlagType.Delegate) > 0) return def; - if (type.IndexOf('.') < 0) + if (!type.Contains('.')) { - string dotType = '.' + type; - MemberList imports = ASContext.Context.ResolveImports(inFile); + var dotType = '.' + type; + var imports = ASContext.Context.ResolveImports(inFile); foreach (MemberModel import in imports) if (import.Type.EndsWithOrdinal(dotType)) { @@ -528,22 +667,22 @@ private static MemberModel ResolveDelegate(string type, FileModel inFile) } } - MemberList known = ASContext.Context.GetAllProjectClasses(); + var known = ASContext.Context.GetAllProjectClasses(); foreach (MemberModel def in known) if (def.Type == type && (def.Flags & FlagType.Delegate) > 0) return def; return null; } - private static void GenerateDefaultHandlerName(ScintillaControl sci, int position, int targetPos, string eventName, bool closeBrace) + static void GenerateDefaultHandlerName(ScintillaControl sci, int position, int targetPos, string eventName, bool closeBrace) { string target = null; - int contextOwnerPos = GetContextOwnerEndPos(sci, sci.WordStartPosition(targetPos, true)); + var contextOwnerPos = GetContextOwnerEndPos(sci, sci.WordStartPosition(targetPos, true)); if (contextOwnerPos != -1) { - ASResult contextOwnerResult = ASComplete.GetExpressionType(sci, contextOwnerPos); - if (contextOwnerResult != null && !contextOwnerResult.IsNull() - && contextOwnerResult.Member != null) + var contextOwnerResult = ASComplete.GetExpressionType(sci, contextOwnerPos); + if (contextOwnerResult is not null && !contextOwnerResult.IsNull() + && contextOwnerResult.Member is not null) { if (contextOwnerResult.Member.Name == "contentLoaderInfo" && sci.CharAt(contextOwnerPos) == '.') { @@ -552,110 +691,83 @@ private static void GenerateDefaultHandlerName(ScintillaControl sci, int positio if (contextOwnerPos != -1) { contextOwnerResult = ASComplete.GetExpressionType(sci, contextOwnerPos); - if (contextOwnerResult != null && !contextOwnerResult.IsNull() - && contextOwnerResult.Member != null) + if (contextOwnerResult is not null && !contextOwnerResult.IsNull() + && contextOwnerResult.Member is not null) { target = contextOwnerResult.Member.Name; } } } - else - { - target = contextOwnerResult.Member.Name; - } + else target = contextOwnerResult.Member.Name; } } eventName = Camelize(eventName.Substring(eventName.LastIndexOf('.') + 1)); - if (target != null) target = target.TrimStart(new char[] { '_' }); + target = target?.TrimStart('_'); switch (ASContext.CommonSettings.HandlerNamingConvention) { case HandlerNamingConventions.handleTargetEventName: - if (target == null) contextToken = "handle" + Capitalize(eventName); + if (target is null) contextToken = "handle" + Capitalize(eventName); else contextToken = "handle" + Capitalize(target) + Capitalize(eventName); break; case HandlerNamingConventions.onTargetEventName: - if (target == null) contextToken = "on" + Capitalize(eventName); + if (target is null) contextToken = "on" + Capitalize(eventName); else contextToken = "on" + Capitalize(target) + Capitalize(eventName); break; case HandlerNamingConventions.target_eventNameHandler: - if (target == null) contextToken = eventName + "Handler"; + if (target is null) contextToken = eventName + "Handler"; else contextToken = target + "_" + eventName + "Handler"; break; default: //HandlerNamingConventions.target_eventName - if (target == null) contextToken = eventName; + if (target is null) contextToken = eventName; else contextToken = target + "_" + eventName; break; } - char c = (char)sci.CharAt(position - 1); + var c = (char)sci.CharAt(position - 1); if (c == ',') InsertCode(position, "$(Boundary) " + contextToken + "$(Boundary)", sci); else InsertCode(position, contextToken, sci); position = sci.WordEndPosition(position + 1, true); sci.SetSel(position, position); c = (char)sci.CharAt(position); - if (c <= 32) if (closeBrace) sci.ReplaceSel(");"); else sci.ReplaceSel(";"); + if (c <= 32) sci.ReplaceSel(closeBrace ? ");" : ";"); sci.SetSel(position, position); } - private static FoundDeclaration GetDeclarationAtLine(int line) + public virtual FoundDeclaration GetDeclarationAtLine(int line) { - FoundDeclaration result = new FoundDeclaration(); - FileModel model = ASContext.Context.CurrentModel; - - foreach (MemberModel member in model.Members) - { - if (member.LineFrom <= line && member.LineTo >= line) - { - result.Member = member; - return result; - } - } - - foreach (ClassModel aClass in model.Classes) + var result = new FoundDeclaration(); + var model = ASContext.Context.CurrentModel; + result.Member = ASComplete.FindMember(line, model.Members.Items); + if (result.Member is null) { - if (aClass.LineFrom <= line && aClass.LineTo >= line) - { - result.InClass = aClass; - foreach (MemberModel member in aClass.Members) - { - if (member.LineFrom <= line && member.LineTo >= line) - { - result.Member = member; - return result; - } - } - return result; - } + result.InClass = ASComplete.FindMember(line, model.Classes); + if (result.InClass is not null) result.Member = ASComplete.FindMember(line, result.InClass.Members.Items); } + result.InClass ??= ClassModel.VoidClass; return result; } protected bool CheckAutoImport(ASResult expr, List options) { if (ASContext.Context.CurrentClass.Equals(expr.RelClass)) return false; - MemberList allClasses = ASContext.Context.GetAllProjectClasses(); - if (allClasses != null) - { - var names = new HashSet(); - List matches = new List(); - string dotToken = "." + contextToken; - foreach (MemberModel member in allClasses) - if (!names.Contains(member.Name) && member.Name.EndsWithOrdinal(dotToken)) - { - matches.Add(member); - names.Add(member.Name); - } - if (matches.Count > 0) + var allClasses = ASContext.Context.GetAllProjectClasses(); + if (allClasses is null) return false; + var names = new HashSet(); + var matches = new List(); + var dotToken = "." + contextToken; + foreach (var member in allClasses) + if (!names.Contains(member.Name) && member.Name.EndsWithOrdinal(dotToken)) { - ShowImportClass(matches, options); - return true; + matches.Add(member); + names.Add(member.Name); } - } - return false; + if (matches.Count == 0) return false; + ShowImportClass(matches, options); + return true; } /// @@ -664,21 +776,36 @@ protected bool CheckAutoImport(ASResult expr, List options) /// internal static string CheckEventType(string name) { - if (name.IndexOf('"') >= 0) return "Event"; - if (name.IndexOf('.') > 0) name = name.Substring(0, name.IndexOf('.')); - ClassModel model = ASContext.Context.ResolveType(name, ASContext.Context.CurrentModel); + if (name.Contains('"')) return "Event"; + if (name.IndexOf('.') is { } index && index > 0) name = name.Substring(0, index); + var model = ASContext.Context.ResolveType(name, ASContext.Context.CurrentModel); if (model.IsVoid() || model.Name == "Event") return "Event"; model.ResolveExtends(); while (!model.IsVoid() && model.Name != "Event") model = model.Extends; - if (model.Name == "Event") return name; - else return "Event"; + return model.Name == "Event" + ? name + : "Event"; + } + + protected virtual string CheckEventType(MemberModel handler, string eventName) + { + if (handler?.Parameters is {Count: > 1} parameters) + { + var parameter = parameters[1]; + if (parameter is not null) + { + if (!parameter.Parameters.IsNullOrEmpty()) return parameter.Parameters[0].Type; + if (parameter.Type is { } type && type != "Function") return type; + } + } + return CheckEventType(eventName); } #endregion #region generators lists - private static void ShowImportClass(List matches, ICollection options) + static void ShowImportClass(IList matches, ICollection options) { if (matches.Count == 1) { @@ -695,7 +822,7 @@ private static void ShowImportClass(List matches, ICollection options) + static void ShowPromoteLocalAndAddParameter(FoundDeclaration found, ICollection options) { string label = TextHelper.GetString("ASCompletion.Label.PromoteLocal"); string labelMove = TextHelper.GetString("ASCompletion.Label.MoveDeclarationOnTop"); @@ -705,233 +832,237 @@ private static void ShowPromoteLocalAndAddParameter(FoundDeclaration found, ICol options.Add(new GeneratorItem(labelParam, GeneratorJobType.AddAsParameter, found.Member, found.InClass)); } - private static void ShowConvertToConst(FoundDeclaration found, ICollection options) + static void ShowConvertToConst(FoundDeclaration found, ICollection options) { string label = TextHelper.GetString("ASCompletion.Label.ConvertToConst"); options.Add(new GeneratorItem(label, GeneratorJobType.ConvertToConst, found.Member, found.InClass)); } - private static void ShowImplementInterface(FoundDeclaration found, ICollection options) + static void ShowImplementInterface(FoundDeclaration found, ICollection options) { string label = TextHelper.GetString("ASCompletion.Label.ImplementInterface"); options.Add(new GeneratorItem(label, GeneratorJobType.ImplementInterface, null, found.InClass)); } - private static void ShowNewVarList(FoundDeclaration found, ICollection options) - { - bool generateClass = true; - ScintillaControl sci = ASContext.CurSciControl; - int currentPos = sci.CurrentPos; - ASResult exprAtCursor = ASComplete.GetExpressionType(sci, sci.WordEndPosition(currentPos, true)); - if (exprAtCursor == null || exprAtCursor.InClass == null || found.InClass.QualifiedName.Equals(exprAtCursor.RelClass.QualifiedName)) - exprAtCursor = null; - ASResult exprLeft = null; - int curWordStartPos = sci.WordStartPosition(currentPos, true); - if ((char)sci.CharAt(curWordStartPos - 1) == '.') exprLeft = ASComplete.GetExpressionType(sci, curWordStartPos - 1); - if (exprLeft != null && exprLeft.Type == null) exprLeft = null; - if (exprLeft != null) - { - if (exprLeft.Type.InFile != null && !File.Exists(exprLeft.Type.InFile.FileName)) return; - generateClass = false; - ClassModel curClass = ASContext.Context.CurrentClass; - if (!IsHaxe) - { - if (exprLeft.Type.Equals(curClass)) exprLeft = null; - } - else - { - while (!curClass.IsVoid()) - { - if (curClass.Equals(exprLeft.Type)) - { - exprLeft = null; - break; - } - curClass.ResolveExtends(); - curClass = curClass.Extends; - } - } - } - string label; - if ((exprAtCursor != null && exprAtCursor.RelClass != null && (exprAtCursor.RelClass.Flags & FlagType.Interface) > 0) - || (found.InClass != null && (found.InClass.Flags & FlagType.Interface) > 0)) - { - label = TextHelper.GetString("ASCompletion.Label.GenerateFunctionInterface"); - options.Add(new GeneratorItem(label, GeneratorJobType.FunctionPublic, found.Member, found.InClass)); - } - else - { - string textAtCursor = sci.GetWordFromPosition(currentPos); - bool isConst = textAtCursor != null && textAtCursor.ToUpper().Equals(textAtCursor); - if (isConst) + protected virtual void ShowNewVarList(ScintillaControl sci, ASResult expr, FoundDeclaration found, ICollection options) + { + if (expr.InClass is null || found.InClass.QualifiedName.Equals(expr.RelClass.QualifiedName)) + expr = null; + ASResult exprLeft = null; + var currentPos = sci.CurrentPos; + var curWordStartPos = sci.WordStartPosition(currentPos, true); + if ((char)sci.CharAt(curWordStartPos - 1) == '.') exprLeft = ASComplete.GetExpressionType(sci, curWordStartPos - 1); + if (exprLeft is not null && exprLeft.Type is null) exprLeft = null; + var generateClass = true; + if (exprLeft is not null) + { + if (!File.Exists(exprLeft.Type.InFile?.FileName)) return; + generateClass = false; + var curClass = ASContext.Context.CurrentClass; + if (!IsHaxe) + { + if (exprLeft.Type.Equals(curClass)) exprLeft = null; + } + else { - label = TextHelper.GetString("ASCompletion.Label.GenerateConstant"); - options.Add(new GeneratorItem(label, GeneratorJobType.Constant, found.Member, found.InClass)); - } - - bool genProtectedDecl = GetDefaultVisibility(found.InClass) == Visibility.Protected; - if (exprAtCursor == null && exprLeft == null) - { - if (genProtectedDecl) label = TextHelper.GetString("ASCompletion.Label.GenerateProtectedVar"); - else label = TextHelper.GetString("ASCompletion.Label.GeneratePrivateVar"); - options.Add(new GeneratorItem(label, GeneratorJobType.Variable, found.Member, found.InClass)); + curClass.ResolveExtends(); + while (!curClass.IsVoid()) + { + if (curClass.Equals(exprLeft.Type)) + { + exprLeft = null; + break; + } + curClass = curClass.Extends; + } } + } + + var textAtCursor = sci.GetWordFromPosition(currentPos); + string label; + if (textAtCursor is not null && textAtCursor.ToUpper().Equals(textAtCursor)) + { + label = TextHelper.GetString("ASCompletion.Label.GenerateConstant"); + options.Add(new GeneratorItem(label, GeneratorJobType.Constant, found.Member, found.InClass)); + } - label = TextHelper.GetString("ASCompletion.Label.GeneratePublicVar"); - options.Add(new GeneratorItem(label, GeneratorJobType.VariablePublic, found.Member, found.InClass)); + bool genProtectedDecl = GetDefaultVisibility(found.InClass) == Visibility.Protected; + if (expr is null && exprLeft is null) + { + if (genProtectedDecl) label = TextHelper.GetString("ASCompletion.Label.GenerateProtectedVar"); + else label = TextHelper.GetString("ASCompletion.Label.GeneratePrivateVar"); + options.Add(new GeneratorItem(label, GeneratorJobType.Variable, found.Member, found.InClass)); + } - if (exprAtCursor == null && exprLeft == null) - { - if (genProtectedDecl) label = TextHelper.GetString("ASCompletion.Label.GenerateProtectedFunction"); - else label = TextHelper.GetString("ASCompletion.Label.GeneratePrivateFunction"); - options.Add(new GeneratorItem(label, GeneratorJobType.Function, found.Member, found.InClass)); - } - - label = TextHelper.GetString("ASCompletion.Label.GenerateFunctionPublic"); - options.Add(new GeneratorItem(label, GeneratorJobType.FunctionPublic, found.Member, found.InClass)); + label = TextHelper.GetString("ASCompletion.Label.GeneratePublicVar"); + options.Add(new GeneratorItem(label, GeneratorJobType.VariablePublic, found.Member, found.InClass)); - if (generateClass) - { - label = TextHelper.GetString("ASCompletion.Label.GenerateClass"); - options.Add(new GeneratorItem(label, GeneratorJobType.Class, found.Member, found.InClass)); - } + if (expr is null && exprLeft is null) + { + if (genProtectedDecl) label = TextHelper.GetString("ASCompletion.Label.GenerateProtectedFunction"); + else label = TextHelper.GetString("ASCompletion.Label.GeneratePrivateFunction"); + options.Add(new GeneratorItem(label, GeneratorJobType.Function, found.Member, found.InClass)); + } + + label = TextHelper.GetString("ASCompletion.Label.GenerateFunctionPublic"); + options.Add(new GeneratorItem(label, GeneratorJobType.FunctionPublic, found.Member, found.InClass)); + + if (generateClass) + { + label = TextHelper.GetString("ASCompletion.Label.GenerateClass"); + options.Add(new GeneratorItem(label, GeneratorJobType.Class, found.Member, found.InClass)); } } - private static void ShowChangeMethodDeclList(FoundDeclaration found, ICollection options) + static void ShowChangeMethodDeclList(FoundDeclaration found, ICollection options) { - string label = TextHelper.GetString("ASCompletion.Label.ChangeMethodDecl"); + var label = TextHelper.GetString("ASCompletion.Label.ChangeMethodDecl"); options.Add(new GeneratorItem(label, GeneratorJobType.ChangeMethodDecl, found.Member, found.InClass)); } - private static void ShowChangeConstructorDeclarationList(FoundDeclaration found, IList parameters, ICollection options) + static void ShowChangeConstructorDeclarationList(FoundDeclaration found, IList parameters, ICollection options) { var label = TextHelper.GetString("ASCompletion.Label.ChangeConstructorDecl"); options.Add(new GeneratorItem(label, GeneratorJobType.ChangeConstructorDecl, found.Member, found.InClass, parameters)); } - private static void ShowNewMethodList(FoundDeclaration found, ICollection options) + protected virtual void ShowNewMethodList(ScintillaControl sci, ASResult expr, FoundDeclaration found, ICollection options) { - ScintillaControl sci = ASContext.CurSciControl; - ASResult result = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); - if (result == null || result.RelClass == null || found.InClass.QualifiedName.Equals(result.RelClass.QualifiedName)) - result = null; + if (expr.RelClass is null || found.InClass.QualifiedName.Equals(expr.RelClass.QualifiedName)) + expr = null; string label; - ClassModel inClass = result != null ? result.RelClass : found.InClass; - bool isInterface = (inClass.Flags & FlagType.Interface) > 0; - if (!isInterface && result == null) - { - if (GetDefaultVisibility(found.InClass) == Visibility.Protected) + var inClass = expr is not null ? expr.RelClass : found.InClass; + var isInterface = (inClass.Flags & FlagType.Interface) > 0; + if (!isInterface && expr is null) + { + if (GetDefaultVisibility(found.InClass) == Visibility.Protected) label = TextHelper.GetString("ASCompletion.Label.GenerateProtectedFunction"); else label = TextHelper.GetString("ASCompletion.Label.GeneratePrivateFunction"); options.Add(new GeneratorItem(label, GeneratorJobType.Function, found.Member, found.InClass)); } - if (isInterface) label = TextHelper.GetString("ASCompletion.Label.GenerateFunctionInterface"); + if (isInterface) label = TextHelper.GetString("ASCompletion.Label.GenerateFunctionInterface"); else label = TextHelper.GetString("ASCompletion.Label.GenerateFunctionPublic"); options.Add(new GeneratorItem(label, GeneratorJobType.FunctionPublic, found.Member, found.InClass)); label = TextHelper.GetString("ASCompletion.Label.GeneratePublicCallback"); options.Add(new GeneratorItem(label, GeneratorJobType.VariablePublic, found.Member, found.InClass)); } - private static void ShowAssignStatementToVarList(FoundDeclaration found, StatementReturnType data, ICollection options) + static void ShowAssignStatementToVarList(FoundDeclaration found, StatementReturnType data, ICollection options) { var label = TextHelper.GetString("ASCompletion.Label.AssignStatementToVar"); options.Add(new GeneratorItem(label, GeneratorJobType.AssignStatementToVar, found.Member, found.InClass, data)); } - private static void ShowNewClassList(FoundDeclaration found, ICollection options) => ShowNewClassList(found, null, options); + static void ShowGenerateClassList(FoundDeclaration found, ICollection options) => ShowGenerateClassList(found, null, options); - private static void ShowNewClassList(FoundDeclaration found, ASExpr expr, ICollection options) + static void ShowGenerateClassList(FoundDeclaration found, ASExpr expr, ICollection options) { var label = TextHelper.GetString("ASCompletion.Label.GenerateClass"); options.Add(new GeneratorItem(label, GeneratorJobType.Class, found.Member, found.InClass, expr)); } - private static void ShowConstructorAndToStringList(FoundDeclaration found, bool hasConstructor, bool hasToString, ICollection options) + static void ShowGenerateInterfaceList(ASResult expr, FoundDeclaration found, ICollection options) + { + var label = TextHelper.GetString("ASCompletion.Label.GenerateInterface"); + options.Add(new GeneratorItem(label, GeneratorJobType.Interface, found.Member, found.InClass, expr)); + } + + static void ShowConstructorAndToStringList(FoundDeclaration found, bool hasConstructor, bool hasToString, ICollection options) { if (!hasConstructor) { - string label = TextHelper.GetString("ASCompletion.Label.GenerateConstructor"); + var label = TextHelper.GetString("ASCompletion.Label.GenerateConstructor"); options.Add(new GeneratorItem(label, GeneratorJobType.Constructor, found.Member, found.InClass)); } if (!hasToString) { - string label = TextHelper.GetString("ASCompletion.Label.GenerateToString"); + var label = TextHelper.GetString("ASCompletion.Label.GenerateToString"); options.Add(new GeneratorItem(label, GeneratorJobType.ToString, found.Member, found.InClass)); } } - private static void ShowEventMetatagList(FoundDeclaration found, ICollection options) + static void ShowEventMetatagList(FoundDeclaration found, ICollection options) { string label = TextHelper.GetString("ASCompletion.Label.GenerateEventMetatag"); options.Add(new GeneratorItem(label, GeneratorJobType.EventMetatag, found.Member, found.InClass)); } - private static void ShowFieldFromParameter(FoundDeclaration found, ICollection options) + static void ShowFieldFromParameter(FoundDeclaration found, ICollection options) { - Hashtable parameters = new Hashtable(); - parameters["scope"] = GetDefaultVisibility(found.InClass); + var parameters = new Hashtable {["scope"] = GetDefaultVisibility(found.InClass)}; string label; if (GetDefaultVisibility(found.InClass) == Visibility.Protected) label = TextHelper.GetString("ASCompletion.Label.GenerateProtectedFieldFromParameter"); else label = TextHelper.GetString("ASCompletion.Label.GeneratePrivateFieldFromParameter"); options.Add(new GeneratorItem(label, GeneratorJobType.FieldFromParameter, found.Member, found.InClass, parameters)); - parameters = new Hashtable(); - parameters["scope"] = Visibility.Public; + parameters = new Hashtable {["scope"] = Visibility.Public}; label = TextHelper.GetString("ASCompletion.Label.GeneratePublicFieldFromParameter"); options.Add(new GeneratorItem(label, GeneratorJobType.FieldFromParameter, found.Member, found.InClass, parameters)); } - private static void ShowAddInterfaceDefList(FoundDeclaration found, IEnumerable interfaces, ICollection options) + static void ShowAddInterfaceDefList(FoundDeclaration found, IEnumerable interfaces, ICollection options) { var label = TextHelper.GetString("ASCompletion.Label.AddInterfaceDef"); foreach (var interf in interfaces) { - options.Add(new GeneratorItem(String.Format(label, interf), GeneratorJobType.AddInterfaceDef, found.Member, found.InClass, interf)); + options.Add(new GeneratorItem(string.Format(label, interf), GeneratorJobType.AddInterfaceDef, found.Member, found.InClass, interf)); } } - private static void ShowDelegateList(FoundDeclaration found, ICollection options) + static void ShowDelegateList(FoundDeclaration found, ICollection options) { - string label = String.Format(TextHelper.GetString("ASCompletion.Label.GenerateHandler"), "Delegate"); + string label = string.Format(TextHelper.GetString("ASCompletion.Label.GenerateHandler"), "Delegate"); options.Add(new GeneratorItem(label, GeneratorJobType.Delegate, found.Member, found.InClass)); } internal static void ShowEventList(FoundDeclaration found, List options) { - string tmp = TextHelper.GetString("ASCompletion.Label.GenerateHandler"); - string labelEvent = String.Format(tmp, "Event"); - string labelDataEvent = String.Format(tmp, "DataEvent"); - string labelContext = String.Format(tmp, contextParam); - string[] choices; - if (contextParam != "Event") choices = new string[] { labelContext, labelEvent }; - else if (HasDataEvent()) choices = new string[] { labelEvent, labelDataEvent }; - else choices = new string[] { labelEvent }; + var tmp = TextHelper.GetString("ASCompletion.Label.GenerateHandler"); + var labelEvent = string.Format(tmp, "Event"); + var labelContext = string.Format(tmp, contextParam); + string[] choices = null; + if (contextParam != "Event") + { + var type = ASContext.Context.ResolveType(contextParam, ASContext.Context.CurrentModel); + type.ResolveExtends(); + while (!type.IsVoid()) + { + if (type.Name == "Event") + { + choices = new[] { labelContext, labelEvent }; + break; + } + type = type.Extends; + } + choices ??= new[] {labelContext}; + } + else if (HasDataEvent()) + { + var labelDataEvent = string.Format(tmp, "DataEvent"); + choices = new[] { labelEvent, labelDataEvent }; + } + else choices = new[] { labelEvent }; - for (int i = 0; i < choices.Length; i++) + foreach (var choice in choices) { - var choice = choices[i]; options.Add(new GeneratorItem(choice, choice == labelContext ? GeneratorJobType.ComplexEvent : GeneratorJobType.BasicEvent, found.Member, found.InClass)); } - } - - private static bool HasDataEvent() - { - return !ASContext.Context.ResolveType("flash.events.DataEvent", ASContext.Context.CurrentModel).IsVoid(); } - private static void ShowGetSetList(FoundDeclaration found, ICollection options) + static bool HasDataEvent() => !ASContext.Context.ResolveType("flash.events.DataEvent", ASContext.Context.CurrentModel).IsVoid(); + + static void ShowGetSetList(FoundDeclaration found, ICollection options) { - string name = GetPropertyNameFor(found.Member); - ASResult result = new ASResult(); - ClassModel curClass = ASContext.Context.CurrentClass; + var name = GetPropertyNameFor(found.Member); + var result = new ASResult(); + var curClass = ASContext.Context.CurrentClass; ASComplete.FindMember(name, curClass, result, FlagType.Getter, 0); - bool hasGetter = !result.IsNull(); + var hasGetter = !result.IsNull(); ASComplete.FindMember(name, curClass, result, FlagType.Setter, 0); - bool hasSetter = !result.IsNull(); + var hasSetter = !result.IsNull(); if (hasGetter && hasSetter) return; if (!hasGetter && !hasSetter) { @@ -942,7 +1073,7 @@ private static void ShowGetSetList(FoundDeclaration found, ICollection options) + static void ShowGetterList(FoundDeclaration found, ICollection options) { var name = GetPropertyNameFor(found.Member); var result = new ASResult(); @@ -952,7 +1083,7 @@ private static void ShowGetterList(FoundDeclaration found, ICollection options) + static void ShowSetterList(FoundDeclaration found, ICollection options) { var name = GetPropertyNameFor(found.Member); var result = new ASResult(); @@ -966,7 +1097,7 @@ private static void ShowSetterList(FoundDeclaration found, ICollection; - if (parameters == null) ChangeConstructorDecl(sci, inClass); - else ChangeConstructorDecl(sci, inClass, parameters); + if (data is IList parameters) + ChangeConstructorDecl(sci, inClass, parameters); + else ChangeConstructorDecl(sci, inClass); } finally { @@ -1060,7 +1195,7 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo sci.BeginUndoAction(); try { - GenerateFunctionJob(job, sci, member, detach, inClass); + GenerateFunctionJob(job, sci, member, true, inClass); } finally { @@ -1069,21 +1204,15 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo break; case GeneratorJobType.ImplementInterface: - ClassModel iType = ASContext.Context.ResolveType(contextParam, inClass.InFile ?? ASContext.Context.CurrentModel ); + var iType = ASContext.Context.ResolveType(contextParam, inClass.InFile ?? ASContext.Context.CurrentModel); if (iType.IsVoid()) return; - - latest = GetLatestMemberForFunction(inClass, Visibility.Public, null); - if (latest == null) - latest = FindLatest(0, 0, inClass, false, false); - - if (latest == null) + latest = GetLatestMemberForFunction(inClass, Visibility.Public, null) ?? FindLatest(0, 0, inClass, false, false); + if (latest is null) { position = GetBodyStart(inClass.LineFrom, inClass.LineTo, sci); detach = false; } - else - position = sci.PositionFromLine(latest.LineTo + 1) - ((sci.EOLMode == 0) ? 2 : 1); - + else position = sci.PositionFromLine(latest.LineTo + 1) - ((sci.EOLMode == 0) ? 2 : 1); sci.SetSel(position, position); GenerateImplementation(iType, inClass, sci, detach); break; @@ -1097,10 +1226,10 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo position = GetBodyStart(member.LineFrom, member.LineTo, sci); sci.SetSel(position, position); - string varType = contextMember.Type; + var varType = contextMember.Type; if (varType == "") varType = null; - string template = TemplateUtils.GetTemplate("Variable"); + var template = TemplateUtils.GetTemplate("Variable"); template = TemplateUtils.ReplaceTemplateVariable(template, "Name", contextMember.Name); template = TemplateUtils.ReplaceTemplateVariable(template, "Type", varType); template = TemplateUtils.ReplaceTemplateVariable(template, "Modifiers", null); @@ -1122,14 +1251,11 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo try { if (!RemoveLocalDeclaration(sci, contextMember)) return; - latest = GetLatestMemberForVariable(GeneratorJobType.Variable, inClass, GetDefaultVisibility(inClass), member); - if (latest == null) return; - + if (latest is null) return; position = FindNewVarPosition(sci, inClass, latest); if (position <= 0) return; sci.SetSel(position, position); - var newMember = new MemberModel { Name = contextMember.Name, @@ -1137,9 +1263,20 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo Access = GetDefaultVisibility(inClass) }; if ((member.Flags & FlagType.Static) > 0) newMember.Flags |= FlagType.Access; - + // for example: var f:Function/*(v1:Type):void*/ + if ((contextMember.Flags & FlagType.Function) != 0) + { + newMember.Type = ASContext.Context.CodeComplete.ToFunctionDeclarationString(new MemberModel {Parameters = contextMember.Parameters, Type = newMember.Type}); + } GenerateVariable(newMember, position, detach); sci.SetSel(lookupPosition, lookupPosition); + if (ASContext.Context.Settings.GenerateImports) + { + var imports = new List {newMember.Type}; + var types = GetQualifiedTypes(imports, inClass.InFile); + lookupPosition += AddImportsByName(types, sci.LineFromPosition(lookupPosition)); + sci.SetSel(lookupPosition, lookupPosition); + } } finally { @@ -1157,21 +1294,19 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo { sci.EndUndoAction(); } - break; case GeneratorJobType.AddImport: position = sci.CurrentPos; if ((member.Flags & (FlagType.Class | FlagType.Enum | FlagType.Struct | FlagType.TypeDef)) == 0) { - if (member.InFile == null) break; + if (member.InFile is null) break; member.Type = member.Name; } sci.BeginUndoAction(); try { - int offset = InsertImport(member, true); - position += offset; + position += InsertImport(member, true); sci.SetSel(position, position); } finally @@ -1185,6 +1320,10 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo else GenerateClass(sci, inClass, sci.GetWordFromPosition(sci.CurrentPos)); break; + case GeneratorJobType.Interface: + GenerateInterface(sci, inClass, contextToken); + break; + case GeneratorJobType.ToString: sci.BeginUndoAction(); try @@ -1201,7 +1340,7 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo sci.BeginUndoAction(); try { - GenerateFieldFromParameter(sci, member, inClass, (Visibility)(((Hashtable)data)["scope"])); + GenerateFieldFromParameter(sci, member, inClass, (Visibility) (((Hashtable) data)["scope"])); } finally { @@ -1213,7 +1352,7 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo sci.BeginUndoAction(); try { - AddInterfaceDefJob(sci, member, inClass, (String)data); + AddInterfaceDefJob(member, inClass, (string)data); } finally { @@ -1261,7 +1400,7 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo sci.BeginUndoAction(); try { - if (data is StatementReturnType) AssignStatementToVar(sci, inClass, (StatementReturnType)data); + if (data is StatementReturnType returnType) AssignStatementToVar(sci, inClass, returnType); else AssignStatementToVar(sci, inClass); } finally @@ -1272,290 +1411,282 @@ public static void GenerateJob(GeneratorJobType job, MemberModel member, ClassMo } } - private static void GenerateProperty(GeneratorJobType job, MemberModel member, ClassModel inClass, ScintillaControl sci) + protected virtual void GenerateProperty(GeneratorJobType job, ScintillaControl sci, ClassModel inClass, MemberModel member) { - string name = GetPropertyNameFor(member); - PropertiesGenerationLocations location = ASContext.CommonSettings.PropertiesGenerationLocation; - var latest = TemplateUtils.GetTemplateBlockMember(sci, TemplateUtils.GetBoundary("AccessorsMethods")); - if (latest != null) - { - location = PropertiesGenerationLocations.AfterLastPropertyDeclaration; - } - else - { - if (location == PropertiesGenerationLocations.AfterLastPropertyDeclaration) + var name = GetPropertyNameFor(member); + PropertiesGenerationLocations location; + var latest = TemplateUtils.GetTemplateBlockMember(sci, TemplateUtils.GetBoundary("AccessorsMethods")); + if (latest != null) location = PropertiesGenerationLocations.AfterLastPropertyDeclaration; + else + { + location = ASContext.CommonSettings.PropertiesGenerationLocation; + if (location == PropertiesGenerationLocations.AfterLastPropertyDeclaration) { - if (IsHaxe) - { - if (job == GeneratorJobType.Setter) latest = FindMember("get_" + (name ?? member.Name), inClass); - else if (job == GeneratorJobType.Getter) latest = FindMember("set_" + (name ?? member.Name), inClass); - if (latest == null) latest = FindLatest(FlagType.Function, 0, inClass, false, false); - } - else - { - if (job == GeneratorJobType.Getter || job == GeneratorJobType.Setter) latest = FindMember(name ?? member.Name, inClass); - if (latest == null) latest = FindLatest(FlagType.Getter | FlagType.Setter, 0, inClass, false, false); - } - } - else latest = member; - } - if (latest == null) return; - - sci.BeginUndoAction(); - try - { - if (IsHaxe) - { - if (name == null) name = member.Name; - string args = "(default, default)"; - if (job == GeneratorJobType.GetterSetter) args = "(get, set)"; - else if (job == GeneratorJobType.Getter) args = "(get, null)"; - else if (job == GeneratorJobType.Setter) args = "(default, set)"; - MakeHaxeProperty(sci, member, args); - } - else - { - if ((member.Access & Visibility.Public) > 0) // hide member - { - MakePrivate(sci, member, inClass); - } - if (name == null) // rename var with starting underscore - { - name = member.Name; - string newName = GetNewPropertyNameFor(member); - if (RenameMember(sci, member, newName)) member.Name = newName; - } - } + if (job == GeneratorJobType.Getter || job == GeneratorJobType.Setter) + latest = ASComplete.FindMember(name ?? member.Name, inClass); + latest ??= FindLatest(FlagType.Getter | FlagType.Setter, 0, inClass, false, false); + } + else latest = member; + } + if (latest is null) return; + sci.BeginUndoAction(); + try + { + if ((member.Access & Visibility.Public) > 0) MakePrivate(sci, member, inClass); + if (name is null) // rename var with starting underscore + { + name = member.Name; + var newName = GetNewPropertyNameFor(member); + if (RenameMember(sci, member, newName)) member.Name = newName; + } var startsWithNewLine = true; - var endsWithNewLine = false; + var endsWithNewLine = false; int atLine; if (location == PropertiesGenerationLocations.BeforeVariableDeclaration) atLine = latest.LineTo; - else + else if (job == GeneratorJobType.Getter && (latest.Flags & (FlagType.Dynamic | FlagType.Function)) != 0) { - if (job == GeneratorJobType.Getter && (latest.Flags & (FlagType.Dynamic | FlagType.Function)) != 0) - { - atLine = latest.LineFrom; - var declaration = GetDeclarationAtLine(atLine - 1); - startsWithNewLine = declaration.Member != null; - endsWithNewLine = true; - } - else atLine = latest.LineTo + 1; + atLine = latest.LineFrom; + var declaration = GetDeclarationAtLine(atLine - 1); + startsWithNewLine = declaration.Member != null; + endsWithNewLine = true; } - var position = sci.PositionFromLine(atLine) - ((sci.EOLMode == 0) ? 2 : 1); - sci.SetSel(position, position); - if (job == GeneratorJobType.GetterSetter) - { - sci.SetSel(position, position); - GenerateGetterSetter(name, member, position); - } - else - { - if (job == GeneratorJobType.Setter) - { - sci.SetSel(position, position); - GenerateSetter(name, member, position); - } - else if (job == GeneratorJobType.Getter) - { - sci.SetSel(position, position); - GenerateGetter(name, member, position, startsWithNewLine, endsWithNewLine); - } - } - } - finally - { - sci.EndUndoAction(); - } - } - + else atLine = latest.LineTo + 1; + var position = sci.PositionFromLine(atLine) - ((sci.EOLMode == 0) ? 2 : 1); + sci.SetSel(position, position); + // for example: private var foo:Function/*(v1:*):void*/ + if ((member.Flags & FlagType.Function) != 0) + { + member = member.Clone(); + member.Type = ASContext.Context.CodeComplete.ToFunctionDeclarationString(member); + } + if (job == GeneratorJobType.GetterSetter) GenerateGetterSetter(name, member, position); + else if (job == GeneratorJobType.Setter) GenerateSetter(name, member, position); + else if (job == GeneratorJobType.Getter) GenerateGetter(name, member, position, startsWithNewLine, endsWithNewLine); + } + finally + { + sci.EndUndoAction(); + } + } + static void AssignStatementToVar(ScintillaControl sci, ClassModel inClass) { var currentLine = sci.CurrentLine; - var returnType = GetStatementReturnType(sci, inClass, sci.GetLine(currentLine), sci.PositionFromLine(currentLine)); - AssignStatementToVar(sci, inClass, returnType); + var returnType = GetStatementReturnType(sci, inClass, sci.GetLine(currentLine), sci.PositionFromLine(currentLine)); + AssignStatementToVar(sci, inClass, returnType); } + static void AssignStatementToVar(ScintillaControl sci, ClassModel inClass, StatementReturnType returnType) { - var ctx = inClass.InFile.Context; - var resolve = returnType.resolve; + var ctx = inClass.InFile.Context; + var resolve = returnType.Resolve; + string type = null; List expressions = null; var context = resolve.Context; if (context != null) { - var operators = ctx.Features.ArithmeticOperators - .Select(it => it.ToString()) + // for example: typeof v, delete o[k], ... + if (((ASGenerator) ctx.CodeGenerator).AssignStatementToVar(sci, inClass, context)) return; + // for example: 1 + 1, 1 << 1, ... + var operators = Enumerable.ToHashSet(ctx.Features.ArithmeticOperators + .Select(static it => it.ToString()) .Concat(ctx.Features.IncrementDecrementOperators) - .ToHashSet(); + .Concat(ctx.Features.BitwiseOperators) + .Concat(ctx.Features.BooleanOperators) + .Concat(ctx.Features.TernaryOperators)); var sep = new[] {' '}; - var isValid = new Func((c) => c.Separator.Contains(' ') + var isValid = new Func(c => c.Separator.Contains(' ') && c.Separator.Split(sep, StringSplitOptions.RemoveEmptyEntries).Any(it => operators.Contains(it.Trim()))); if (operators.Contains(context.Separator) || operators.Contains(context.RightOperator) || isValid(context)) { + if (context.Separator == "/" || context.Separator == "%") type = ctx.Features.numberKey; var current = resolve; context = current.Context; expressions = new List {current}; var rop = false; while (operators.Contains(context.Separator) || (rop = operators.Contains(context.RightOperator)) || isValid(context)) { + if (type is null && (context.Separator == "/" || context.Separator == "%")) type = ctx.Features.numberKey; var position = rop ? context.PositionExpression : context.SeparatorPosition; current = ASComplete.GetExpressionType(sci, position, false, true); - if (current == null || current.IsNull()) break; + if (current is null || current.IsNull()) break; expressions.Add(current); context = current.Context; rop = false; } } } - string type = null; - if (resolve.Member == null && (resolve.Type.Flags & FlagType.Class) != 0 + int pos; + if (expressions is null) pos = GetStartOfStatement(resolve); + else + { + var last = expressions.Last(); + pos = last.Context.Separator != ";" ? last.Context.SeparatorPosition : last.Context.PositionExpression; + var first = expressions.First(); + if (ctx.Features.BooleanOperators.Contains(first.Context.Separator)) type = ctx.Features.booleanKey; + } + if (type is null + && resolve.Member is null && resolve.Type.Flags.HasFlag(FlagType.Class) && resolve.Type.Name != ctx.Features.booleanKey && resolve.Type.Name != "Function" && !string.IsNullOrEmpty(resolve.Path) && !char.IsDigit(resolve.Path[0])) { - var expr = ASComplete.GetExpression(sci, returnType.position); + var expr = ASComplete.GetExpression(sci, returnType.Position); if (string.IsNullOrEmpty(expr.WordBefore)) { var characters = ScintillaControl.Configuration.GetLanguage(ctx.Settings.LanguageId.ToLower()).characterclass.Characters; if (resolve.Path.All(it => characters.Contains(it))) { - if (inClass.InFile.haXe) type = "Class"; - else type = ctx.ResolveType("Class", resolve.InFile).QualifiedName; + type = inClass.InFile.haXe + ? "Class" + : ctx.ResolveType("Class", resolve.InFile).QualifiedName; } } } - var word = returnType.word; + var word = returnType.Word; if (!string.IsNullOrEmpty(word) && char.IsDigit(word[0])) word = null; string varname = null; if (string.IsNullOrEmpty(type) && !resolve.IsNull()) { if (resolve.Member?.Type != null) type = resolve.Member.Type; - else if (resolve.Type?.Name != null) type = resolve.Type.QualifiedName; + else if (resolve.Type?.Name != null) + { + type = resolve.Type.QualifiedName; + if (resolve.Type.IndexType == "*") type += ".<*>"; + else if (resolve.Type.FullName.Contains(".")) type = resolve.Type.FullName.Replace(".", ".>"); + } + if (resolve.Member?.Name != null) varname = GuessVarName(resolve.Member.Name, type); } if (!string.IsNullOrEmpty(word) && (string.IsNullOrEmpty(type) || Regex.IsMatch(type, "(<[^]]+>)"))) word = null; if (type == ctx.Features.voidKey) type = null; - if (varname == null) varname = GuessVarName(word, type); + varname ??= GuessVarName(word, type); if (varname != null && varname == word) varname = varname.Length == 1 ? varname + "1" : varname[0] + ""; - varname = AvoidKeyword(varname); - string cleanType = null; - if (type != null) cleanType = FormatType(GetShortType(type)); - - string template = TemplateUtils.GetTemplate("AssignVariable"); - template = TemplateUtils.ReplaceTemplateVariable(template, "Name", varname); - template = TemplateUtils.ReplaceTemplateVariable(template, "Type", cleanType); + ((ASGenerator) ctx.CodeGenerator).AssignStatementToVar(sci, pos, varname, type); + } - int pos; - if (expressions == null) pos = GetStartOfStatement(sci, sci.CurrentPos, resolve); - else + protected virtual void AssignStatementToVar(ScintillaControl sci, int position, string name, string type) + { + var template = TemplateUtils.GetTemplate("AssignVariable"); + template = TemplateUtils.ReplaceTemplateVariable(template, "Name", AvoidKeyword(name)); + template = TemplateUtils.ReplaceTemplateVariable(template, "Type", GetShortType(type)); + sci.SetSel(position, position); + InsertCode(position, template, sci); + if (ASContext.Context.Settings.GenerateImports && type != null) { - var last = expressions.Last(); - pos = last.Context.Separator != ";" ? last.Context.SeparatorPosition : last.Context.PositionExpression; + var types = GetQualifiedTypes(new [] {type}, ASContext.Context.CurrentModel); + position += AddImportsByName(types, sci.LineFromPosition(position)); + sci.SetSel(position, position); } - sci.SetSel(pos, pos); - InsertCode(pos, template, sci); + } - if (ASContext.Context.Settings.GenerateImports && type != null) + protected virtual bool AssignStatementToVar(ScintillaControl sci, ClassModel inClass, ASExpr expr) + { + var ctx = inClass.InFile.Context; + ClassModel type; + switch (expr.WordBefore) { - var inClassForImport = resolve.InClass ?? resolve.RelClass ?? inClass; - var types = GetQualifiedTypes(new [] {type}, inClassForImport.InFile); - AddImportsByName(types, sci.LineFromPosition(pos)); - } - } - - public static string AvoidKeyword(string word) - { - var features = ASContext.Context.Features; - return features.accessKeywords.Contains(word) - || features.codeKeywords.Contains(word) - || features.declKeywords.Contains(word) - || features.typesKeywords.Contains(word) - || features.typesPreKeys.Contains(word) - ? $"{word}Value" - : word; + case "typeof": + type = ctx.ResolveType(ctx.Features.stringKey, inClass.InFile); + break; + case "delete": + type = ctx.ResolveType(ctx.Features.booleanKey, inClass.InFile); + break; + default: + return false; + } + var varName = GuessVarName(type.Name, type.Type); + varName = AvoidKeyword(varName); + var template = TemplateUtils.GetTemplate("AssignVariable"); + template = TemplateUtils.ReplaceTemplateVariable(template, "Name", varName); + template = TemplateUtils.ReplaceTemplateVariable(template, "Type", type.Name); + var pos = expr.WordBeforePosition; + sci.SetSel(pos, pos); + InsertCode(pos, template, sci); + return true; } - private static void EventMetatag(ScintillaControl sci, ClassModel inClass) + protected internal static string AvoidKeyword(string word) { - ASResult resolve = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); - string line = sci.GetLine(inClass.LineFrom); - int position = sci.PositionFromLine(inClass.LineFrom) + (line.Length - line.TrimStart().Length); + var features = ASContext.Context.Features; + return features.accessKeywords.Contains(word) + || features.codeKeywords.Contains(word) + || features.declKeywords.Contains(word) + || features.typesKeywords.Contains(word) + || features.typesPreKeys.Contains(word) + || features.Literals.Contains(word) + ? $"{word}Value" + : word; + } - string value = resolve.Member.Value; + static void EventMetatag(ScintillaControl sci, MemberModel inClass) + { + var resolve = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); + var line = sci.GetLine(inClass.LineFrom); + var position = sci.PositionFromLine(inClass.LineFrom) + (line.Length - line.TrimStart().Length); + var value = resolve.Member.Value; if (value != null) { - if (value.StartsWith('\"')) - { - value = value.Trim(new char[] { '"' }); - } - else if (value.StartsWith('\'')) - { - value = value.Trim(new char[] { '\'' }); - } + if (value.StartsWith('\"')) value = value.Trim('"'); + else if (value.StartsWith('\'')) value = value.Trim('\''); } else value = resolve.Member.Type; + if (string.IsNullOrEmpty(value)) return; - if (string.IsNullOrEmpty(value)) - return; - - Regex re1 = new Regex("'(?:[^'\\\\]|(?:\\\\\\\\)|(?:\\\\\\\\)*\\\\.{1})*'"); - Regex re2 = new Regex("\"(?:[^\"\\\\]|(?:\\\\\\\\)|(?:\\\\\\\\)*\\\\.{1})*\""); - Match m1 = re1.Match(value); - Match m2 = re2.Match(value); + var re1 = new Regex("'(?:[^'\\\\]|(?:\\\\\\\\)|(?:\\\\\\\\)*\\\\.{1})*'"); + var re2 = new Regex("\"(?:[^\"\\\\]|(?:\\\\\\\\)|(?:\\\\\\\\)*\\\\.{1})*\""); + var m1 = re1.Match(value); + var m2 = re2.Match(value); if (m1.Success || m2.Success) { - Match m = null; - if (m1.Success && m2.Success) m = m1.Index > m2.Index ? m2 : m1; - else if (m1.Success) m = m1; - else m = m2; + Match m = m1.Success switch + { + true when m2.Success => m1.Index > m2.Index ? m2 : m1, + true => m1, + _ => m2 + }; value = value.Substring(m.Index + 1, m.Length - 2); } - string template = TemplateUtils.GetTemplate("EventMetatag"); + var template = TemplateUtils.GetTemplate("EventMetatag"); template = TemplateUtils.ReplaceTemplateVariable(template, "Name", value); template = TemplateUtils.ReplaceTemplateVariable(template, "Type", contextParam); template += "\n$(Boundary)"; AddLookupPosition(); - sci.CurrentPos = position; sci.SetSel(position, position); InsertCode(position, template, sci); } - private static void ConvertToConst(ScintillaControl sci, MemberModel member, ClassModel inClass, bool detach) + static void ConvertToConst(ScintillaControl sci, MemberModel member, ClassModel inClass, bool detach) { - String suggestion = "NEW_CONST"; - String label = TextHelper.GetString("ASCompletion.Label.ConstName"); - String title = TextHelper.GetString("ASCompletion.Title.ConvertToConst"); + var suggestion = "NEW_CONST"; + var label = TextHelper.GetString("ASCompletion.Label.ConstName"); + var title = TextHelper.GetString("ASCompletion.Title.ConvertToConst"); - Hashtable info = new Hashtable(); - info["suggestion"] = suggestion; - info["label"] = label; - info["title"] = title; - DataEvent de = new DataEvent(EventType.Command, "ProjectManager.LineEntryDialog", info); + var info = new Hashtable {["suggestion"] = suggestion, ["label"] = label, ["title"] = title}; + var de = new DataEvent(EventType.Command, "ProjectManager.LineEntryDialog", info); EventManager.DispatchEvent(null, de); - if (!de.Handled) - return; - - suggestion = (string)info["suggestion"]; + if (!de.Handled) return; int position = sci.CurrentPos; int style = sci.BaseStyleAt(position); - MemberModel latest = null; - int wordPosEnd = position + 1; - int wordPosStart = position; - - while (sci.BaseStyleAt(wordPosEnd) == style) wordPosEnd++; - while (sci.BaseStyleAt(wordPosStart - 1) == style) wordPosStart--; + int wordPosEnd = position + 1; + int wordPosStart = position; + + while (sci.BaseStyleAt(wordPosEnd) == style) wordPosEnd++; + while (sci.BaseStyleAt(wordPosStart - 1) == style) wordPosStart--; sci.SetSel(wordPosStart, wordPosEnd); - string word = sci.SelText; + var word = sci.SelText; + suggestion = (string)info["suggestion"]; sci.ReplaceSel(suggestion); - if (member == null) + if (member is null) { detach = false; lookupPosition = -1; @@ -1564,11 +1695,17 @@ private static void ConvertToConst(ScintillaControl sci, MemberModel member, Cla } else { - latest = GetLatestMemberForVariable(GeneratorJobType.Constant, inClass, - Visibility.Private, new MemberModel("", "", FlagType.Static, 0)); + var latest = GetLatestMemberForVariable(GeneratorJobType.Constant, inClass, Visibility.Private, new MemberModel("", "", FlagType.Static, 0)); if (latest != null) { - position = FindNewVarPosition(sci, inClass, latest); + if (!member.Flags.HasFlag(FlagType.Function) && sci.LineFromPosition(wordPosStart) is { } line && latest.LineFrom >= line) + { + position = sci.LineIndentPosition(line); + sci.SetSel(position, position); + sci.NewLine(); + detach = false; + } + else position = FindNewVarPosition(sci, inClass, latest); } else { @@ -1579,46 +1716,33 @@ private static void ConvertToConst(ScintillaControl sci, MemberModel member, Cla sci.SetSel(position, position); } - MemberModel m = NewMember(suggestion, member, FlagType.Variable | FlagType.Constant | FlagType.Static, GetDefaultVisibility(inClass)); - - var features = ASContext.Context.Features; - - switch (style) - { - case 4: - m.Type = features.numberKey; - break; - case 6: - case 7: - m.Type = features.stringKey; - break; - } - + var m = NewMember(suggestion, member, FlagType.Variable | FlagType.Constant | FlagType.Static, GetDefaultVisibility(inClass)); + m.Type = style switch + { + 4 => ASContext.Context.Features.numberKey, + 6 => ASContext.Context.Features.stringKey, + 7 => ASContext.Context.Features.stringKey, + _ => m.Type + }; + m.Value = word; GenerateVariable(m, position, detach); } - private static void ChangeMethodDecl(ScintillaControl sci, ClassModel inClass) + static void ChangeMethodDecl(ScintillaControl sci, ClassModel inClass) { - int wordPos = sci.WordEndPosition(sci.CurrentPos, true); - List functionParameters = ParseFunctionParameters(sci, wordPos); - - ASResult funcResult = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); - if (funcResult == null || funcResult.Member == null) return; + var wordPos = sci.WordEndPosition(sci.CurrentPos, true); + var parameters = ParseFunctionParameters(sci, wordPos); + var funcResult = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); + if (funcResult?.Member is null) return; if (funcResult.InClass != null && !funcResult.InClass.Equals(inClass)) { AddLookupPosition(); lookupPosition = -1; - ASContext.MainForm.OpenEditableDocument(funcResult.InClass.InFile.FileName, true); - sci = ASContext.CurSciControl; - - FileModel fileModel = new FileModel(); - fileModel.Context = ASContext.Context; - ASFileParser parser = new ASFileParser(); - parser.ParseSrc(fileModel, sci.Text); - - foreach (ClassModel cm in fileModel.Classes) + sci = ((ITabbedDocument) PluginBase.MainForm.OpenEditableDocument(funcResult.InClass.InFile.FileName, true)).SciControl; + var fileModel = ASContext.Context.GetCodeModel(sci.Text); + foreach (var cm in fileModel.Classes) { if (cm.QualifiedName.Equals(funcResult.InClass.QualifiedName)) { @@ -1627,12 +1751,10 @@ private static void ChangeMethodDecl(ScintillaControl sci, ClassModel inClass) } } inClass = funcResult.InClass; - ASContext.Context.UpdateContext(inClass.LineFrom); } - MemberList members = inClass.Members; - foreach (MemberModel m in members) + foreach (var m in inClass.Members) { if (m.Equals(funcResult.Member)) { @@ -1641,34 +1763,28 @@ private static void ChangeMethodDecl(ScintillaControl sci, ClassModel inClass) } } - ChangeDecl(sci, inClass, funcResult.Member, functionParameters); + ChangeDecl(sci, inClass, funcResult.Member, parameters); } - private static void ChangeConstructorDecl(ScintillaControl sci, ClassModel inClass) + static void ChangeConstructorDecl(ScintillaControl sci, ClassModel inClass) { var position = sci.WordEndPosition(sci.CurrentPos, true); var parameters = ParseFunctionParameters(sci, position); ChangeConstructorDecl(sci, inClass, parameters); } - private static void ChangeConstructorDecl(ScintillaControl sci, ClassModel inClass, IList parameters) + static void ChangeConstructorDecl(ScintillaControl sci, ClassModel inClass, IList parameters) { var funcResult = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); - if (funcResult == null || funcResult.Type == null) return; + if (funcResult?.Type is null) return; if (!funcResult.Type.Equals(inClass)) { AddLookupPosition(); lookupPosition = -1; - - ASContext.MainForm.OpenEditableDocument(funcResult.Type.InFile.FileName, true); - sci = ASContext.CurSciControl; - - FileModel fileModel = new FileModel(funcResult.Type.InFile.FileName); - fileModel.Context = ASContext.Context; - ASFileParser parser = new ASFileParser(); - parser.ParseSrc(fileModel, sci.Text); - - foreach (ClassModel cm in fileModel.Classes) + PluginBase.MainForm.OpenEditableDocument(funcResult.Type.InFile.FileName, true); + sci = PluginBase.MainForm.CurrentDocument?.SciControl; + var fileModel = ASContext.Context.GetFileModel(funcResult.Type.InFile.FileName); + foreach (var cm in fileModel.Classes) { if (cm.QualifiedName.Equals(funcResult.Type.QualifiedName)) { @@ -1676,27 +1792,16 @@ private static void ChangeConstructorDecl(ScintillaControl sci, ClassModel inCla break; } } - inClass = funcResult.Type; ASContext.Context.UpdateContext(inClass.LineFrom); } - - foreach (MemberModel m in inClass.Members) - { - if ((m.Flags & FlagType.Constructor) > 0) - { - funcResult.Member = m; - break; - } - } - - if (funcResult.Member == null) return; - if (!string.IsNullOrEmpty(ASContext.Context.Features.ConstructorKey)) funcResult.Member.Name = ASContext.Context.Features.ConstructorKey; - + funcResult.Member = inClass.SearchMember(FlagType.Constructor, false); + if (funcResult.Member is null) return; + if (!string.IsNullOrEmpty(ASContext.Context.Features.ConstructorKey)) funcResult.Member.Name = ASContext.Context.Features.ConstructorKey; ChangeDecl(sci, inClass, funcResult.Member, parameters); } - private static void ChangeDecl(ScintillaControl sci, ClassModel inClass, MemberModel memberModel, IList functionParameters) + static void ChangeDecl(ScintillaControl sci, MemberModel inClass, MemberModel memberModel, IList functionParameters) { bool paramsDiffer = false; if (memberModel.Parameters != null) @@ -1706,10 +1811,10 @@ private static void ChangeDecl(ScintillaControl sci, ClassModel inClass, MemberM { if (functionParameters.Count > 0) { - List parameters = memberModel.Parameters; + var parameters = memberModel.Parameters; for (int i = 0; i < parameters.Count; i++) { - MemberModel p = parameters[i]; + var p = parameters[i]; if (p.Type != functionParameters[i].paramType) { paramsDiffer = true; @@ -1729,335 +1834,312 @@ private static void ChangeDecl(ScintillaControl sci, ClassModel inClass, MemberM paramsDiffer = true; } - if (paramsDiffer) + if (!paramsDiffer) return; + int app = 0; + var newParameters = new List(); + var existingParameters = memberModel.Parameters; + for (int i = 0; i < functionParameters.Count; i++) { - int app = 0; - List newParameters = new List(); - List existingParameters = memberModel.Parameters; - for (int i = 0; i < functionParameters.Count; i++) + var p = functionParameters[i]; + if (existingParameters != null + && existingParameters.Count > (i - app) + && existingParameters[i - app].Type == p.paramType) { - FunctionParameter p = functionParameters[i]; - if (existingParameters != null - && existingParameters.Count > (i - app) - && existingParameters[i - app].Type == p.paramType) - { - newParameters.Add(existingParameters[i - app]); - } - else - { - if (existingParameters != null && existingParameters.Count < functionParameters.Count) - { - app++; - } - newParameters.Add(new MemberModel(AvoidKeyword(p.paramName), p.paramType, FlagType.ParameterVar, 0)); - } + newParameters.Add(existingParameters[i - app]); } - memberModel.Parameters = newParameters; - - int posStart = sci.PositionFromLine(memberModel.LineFrom); - int posEnd = sci.LineEndPosition(memberModel.LineTo); - sci.SetSel(posStart, posEnd); - string selectedText = sci.SelText; - Regex rStart = new Regex(@"\s{1}" + memberModel.Name + @"\s*\(([^\)]*)\)(\s*:\s*([^({{|\n|\r|\s|;)]+))?"); - Match mStart = rStart.Match(selectedText); - if (!mStart.Success) - { - return; - } - - int start = mStart.Index + posStart; - int end = start + mStart.Length; - - sci.SetSel(start, end); - - string decl = TemplateUtils.ToDeclarationString(memberModel, TemplateUtils.GetTemplate("MethodDeclaration")); - InsertCode(sci.CurrentPos, "$(Boundary) " + decl, sci); - - // add imports to function argument types - if (ASContext.Context.Settings.GenerateImports && functionParameters.Count > 0) + else { - var l = new string[functionParameters.Count]; - for (var i = 0; i < functionParameters.Count; i++) - { - l[i] = functionParameters[i].paramQualType; - } - var types = GetQualifiedTypes(l, inClass.InFile); - start += AddImportsByName(types, sci.LineFromPosition(end)); + if (existingParameters != null && existingParameters.Count < functionParameters.Count) app++; + newParameters.Add(new MemberModel(AvoidKeyword(p.paramName), GetShortType(p.paramQualType), FlagType.ParameterVar, 0)); } - - sci.SetSel(start, start); } - } - private static void AddAsParameter(ScintillaControl sci, MemberModel member) - { - if (!RemoveLocalDeclaration(sci, contextMember)) return; + memberModel.Parameters = newParameters; - int posStart = sci.PositionFromLine(member.LineFrom); - int posEnd = sci.LineEndPosition(member.LineTo); + var posStart = sci.PositionFromLine(memberModel.LineFrom); + var posEnd = sci.LineEndPosition(memberModel.LineTo); sci.SetSel(posStart, posEnd); - string selectedText = sci.SelText; - Regex rStart = new Regex(@"\s{1}" + member.Name + @"\s*\(([^\)]*)\)(\s*:\s*([^({{|\n|\r|\s|;)]+))?"); - Match mStart = rStart.Match(selectedText); - if (!mStart.Success) - return; + var selectedText = sci.SelText; + var rStart = new Regex(@"\s{1}" + memberModel.Name + @"\s*\(([^\)]*)\)(\s*:\s*([^({{|\n|\r|\s|;)]+))?"); + var mStart = rStart.Match(selectedText); + if (!mStart.Success) return; - int start = mStart.Index + posStart + 1; - int end = mStart.Index + posStart + mStart.Length; + var start = mStart.Index + posStart; + var end = start + mStart.Length; sci.SetSel(start, end); - MemberModel memberCopy = (MemberModel) member.Clone(); - - if (memberCopy.Parameters == null) - memberCopy.Parameters = new List(); - - memberCopy.Parameters.Add(contextMember); - - string template = TemplateUtils.ToDeclarationString(memberCopy, TemplateUtils.GetTemplate("MethodDeclaration")); - InsertCode(start, template, sci); - - int currPos = sci.LineEndPosition(sci.CurrentLine); + var decl = TemplateUtils.ToDeclarationString(memberModel, TemplateUtils.GetTemplate("MethodDeclaration")); + InsertCode(sci.CurrentPos, "$(Boundary) " + decl, sci); - sci.SetSel(currPos, currPos); - sci.CurrentPos = currPos; - } - - private static void AddInterfaceDefJob(ScintillaControl sci, MemberModel member, ClassModel inClass, string interf) - { - var context = ASContext.Context; - ClassModel aType = context.ResolveType(interf, context.CurrentModel); - if (aType.IsVoid()) return; - - FileModel fileModel = ASFileParser.ParseFile(context.CreateFileModel(aType.InFile.FileName)); - foreach (ClassModel cm in fileModel.Classes) + // add imports to function argument types + if (ASContext.Context.Settings.GenerateImports && functionParameters.Count > 0) { - if (cm.QualifiedName.Equals(aType.QualifiedName)) - { - aType = cm; - break; - } + var list = functionParameters.Select(static it => it.paramQualType).ToArray(); + var types = GetQualifiedTypes(list, inClass.InFile); + start += AddImportsByName(types, sci.LineFromPosition(end)); } + sci.SetSel(start, start); + } - string template; - if ((member.Flags & FlagType.Getter) > 0) + static void AddAsParameter(ScintillaControl sci, MemberModel member) + { + if (!RemoveLocalDeclaration(sci, contextMember)) return; + var posStart = sci.PositionFromLine(member.LineFrom); + var posEnd = sci.LineEndPosition(member.LineTo); + sci.SetSel(posStart, posEnd); + var rStart = new Regex(@"\s{1}" + member.Name + @"\s*\(([^\)]*)\)(\s*:\s*([^({{|\n|\r|\s|;)]+))?"); + var mStart = rStart.Match(sci.SelText); + if (!mStart.Success) return; + var start = mStart.Index + posStart + 1; + var end = mStart.Index + posStart + mStart.Length; + sci.SetSel(start, end); + var memberCopy = member.Clone(); + memberCopy.Parameters ??= new List(); + if ((contextMember.Flags & FlagType.Function) != 0 && contextMember.Parameters != null) { - template = TemplateUtils.GetTemplate("IGetter"); + var parameter = contextMember.Clone(); + parameter.Type = ASContext.Context.CodeComplete.ToFunctionDeclarationString(parameter); + memberCopy.Parameters.Add(parameter); } - else if ((member.Flags & FlagType.Setter) > 0) + else memberCopy.Parameters.Add(contextMember); + var template = TemplateUtils.ToDeclarationString(memberCopy, TemplateUtils.GetTemplate("MethodDeclaration")); + InsertCode(start, template, sci); + var position = sci.LineEndPosition(sci.CurrentLine); + sci.SetSel(position, position); + if (ASContext.Context.Settings.GenerateImports) { - template = TemplateUtils.GetTemplate("ISetter"); + var imports = new List {contextMember.Type}; + var types = GetQualifiedTypes(imports, ASContext.Context.CurrentModel); + position += AddImportsByName(types, sci.LineFromPosition(position)); + sci.SetSel(position, position); } - else template = TemplateUtils.GetTemplate("IFunction"); - - ASContext.MainForm.OpenEditableDocument(aType.InFile.FileName, true); - sci = ASContext.CurSciControl; + } - MemberModel latest = GetLatestMemberForFunction(aType, Visibility.Default, new MemberModel()); + static void AddInterfaceDefJob(MemberModel member, MemberModel inClass, string interf) + { + var ctx = ASContext.Context; + var aType = ctx.ResolveType(interf, ctx.CurrentModel); + if (aType.IsVoid()) return; + var fileModel = ctx.GetFileModel(aType.InFile.FileName); + foreach (var cm in fileModel.Classes) + { + if (!cm.QualifiedName.Equals(aType.QualifiedName)) continue; + aType = cm; + break; + } + var sci = ((ITabbedDocument)PluginBase.MainForm.OpenEditableDocument(aType.InFile.FileName, true))?.SciControl; + if (sci is null) return; + var template = ((ASGenerator) ctx.CodeGenerator).GetAddInterfaceDefTemplate(member); + var latest = GetLatestMemberForFunction(aType, Visibility.Default, new MemberModel()); int position; - if (latest == null) - { - position = GetBodyStart(aType.LineFrom, aType.LineTo, sci); - } + if (latest is null) position = GetBodyStart(aType.LineFrom, aType.LineTo, sci); else { position = sci.PositionFromLine(latest.LineTo + 1) - ((sci.EOLMode == 0) ? 2 : 1); template = NewLine + template; } - sci.SetSel(position, position); - sci.CurrentPos = position; - template = TemplateUtils.ReplaceTemplateVariable(template, "Type", member.Type ?? context.Features.voidKey); - template = TemplateUtils.ToDeclarationString(member, template); - template = TemplateUtils.ReplaceTemplateVariable(template, "BlankLine", NewLine); - template = TemplateUtils.ReplaceTemplateVariable(template, "Void", context.Features.voidKey); - - if (context.Settings.GenerateImports) + string type = null; + if ((member.Flags & FlagType.Setter) != 0) { - List importsList = new List(); - List parms = member.Parameters; - if (parms != null && parms.Count > 0) + if (!member.Parameters.IsNullOrEmpty()) { - importsList.AddRange(from t in parms where t.Type != null select t.Type); + var parameter = member.Parameters[0]; + type = (parameter.Flags & FlagType.Function) != 0 + ? ctx.CodeComplete.ToFunctionDeclarationString(parameter) + : parameter.Type; } - if (member.Type != null) importsList.Add(member.Type); - if (importsList.Count > 0) + type ??= member.Type; + if (type == ctx.Features.voidKey) type = ctx.Features.dynamicKey; + } + else type = member.Type ?? ctx.Features.voidKey; + sci.SetSel(position, position); + template = TemplateUtils.ReplaceTemplateVariable(template, "Type", type); + template = TemplateUtils.ToDeclarationString(member, template); + template = TemplateUtils.ReplaceTemplateVariable(template, "BlankLine", NewLine); + template = TemplateUtils.ReplaceTemplateVariable(template, "Void", ctx.Features.voidKey); + if (ctx.Settings.GenerateImports) + { + var imports = new List(); + var parameters = member.Parameters; + if (!parameters.IsNullOrEmpty()) imports.AddRange(from t in parameters where t.Type != null select t.Type); + if (member.Type != null) imports.Add(member.Type); + if (imports.Count > 0) { - var types = GetQualifiedTypes(importsList, inClass.InFile); + var types = GetQualifiedTypes(imports, inClass.InFile); position += AddImportsByName(types, sci.LineFromPosition(position)); } } - sci.SetSel(position, position); - sci.CurrentPos = position; - InsertCode(position, template, sci); } - private static void GenerateFieldFromParameter(ScintillaControl sci, MemberModel member, ClassModel inClass, Visibility scope) + protected virtual string GetAddInterfaceDefTemplate(MemberModel member) { - int funcBodyStart = GetBodyStart(member.LineFrom, member.LineTo, sci, false); - int fbsLine = sci.LineFromPosition(funcBodyStart); - int endPos = sci.LineEndPosition(member.LineTo); + if ((member.Flags & FlagType.Getter) > 0) return TemplateUtils.GetTemplate("IGetter"); + if ((member.Flags & FlagType.Setter) > 0) return TemplateUtils.GetTemplate("ISetter"); + return TemplateUtils.GetTemplate("IFunction"); + } - sci.SetSel(funcBodyStart, endPos); - string body = sci.SelText; - string trimmed = body.TrimStart(); + static void GenerateFieldFromParameter(ScintillaControl sci, MemberModel member, ClassModel inClass, Visibility scope) + { + var bodyStart = GetBodyStart(member.LineFrom, member.LineTo, sci, false); + var fbsLine = sci.LineFromPosition(bodyStart); + var endPos = sci.LineEndPosition(member.LineTo); - Match m = reSuperCall.Match(trimmed); - if (m.Success && m.Index == 0) - { - funcBodyStart = GetEndOfStatement(funcBodyStart + (body.Length - trimmed.Length), endPos, sci); - } + sci.SetSel(bodyStart, endPos); + var body = sci.SelText; + var trimmed = body.TrimStart(); + + var m = reSuperCall.Match(trimmed); + if (m.Success && m.Index == 0) bodyStart = GetEndOfStatement(bodyStart + (body.Length - trimmed.Length), endPos, sci); - funcBodyStart = GetOrSetPointOfInsertion(funcBodyStart, endPos, fbsLine, sci); + bodyStart = GetOrSetPointOfInsertion(bodyStart, endPos, fbsLine, sci); - sci.SetSel(funcBodyStart, funcBodyStart); - sci.CurrentPos = funcBodyStart; + sci.SetSel(bodyStart, bodyStart); - bool isVararg = false; - string paramName = contextMember.Name; + var paramName = contextMember.Name; var paramType = contextMember.Type; - if (paramName.StartsWithOrdinal("...")) - { - paramName = paramName.TrimStart(' ', '.'); - isVararg = true; - } - else if (inClass.InFile.haXe && paramName.StartsWithOrdinal("?")) - { - paramName = paramName.Remove(0, 1); - if (!string.IsNullOrEmpty(paramType) && !paramType.StartsWith("Null<")) paramType = $"Null<{paramType}>"; - } - string varName = paramName; - string scopedVarName = varName; + paramType = ((ASGenerator) ASContext.Context.CodeGenerator).GetFieldTypeFromParameter(paramType, ref paramName); + + var varName = paramName; + var scopedVarName = varName; if ((scope & Visibility.Public) > 0) { - if ((member.Flags & FlagType.Static) > 0) - scopedVarName = inClass.Name + "." + varName; - else - scopedVarName = "this." + varName; + scopedVarName = (member.Flags & FlagType.Static) > 0 + ? inClass.Name + "." + varName + : "this." + varName; } else { - if (ASContext.CommonSettings.PrefixFields.Length > 0 && !varName.StartsWithOrdinal(ASContext.CommonSettings.PrefixFields)) + var prefixFields = ASContext.CommonSettings.PrefixFields; + if (prefixFields.Length > 0 && !varName.StartsWithOrdinal(prefixFields)) { - scopedVarName = varName = ASContext.CommonSettings.PrefixFields + varName; + scopedVarName = varName = prefixFields + varName; } - if (ASContext.CommonSettings.GenerateScope || ASContext.CommonSettings.PrefixFields == "") + if (ASContext.CommonSettings.GenerateScope || prefixFields == "") { - if ((member.Flags & FlagType.Static) > 0) - scopedVarName = inClass.Name + "." + varName; - else - scopedVarName = "this." + varName; + scopedVarName = (member.Flags & FlagType.Static) > 0 + ? inClass.Name + "." + varName + : "this." + varName; } } - string template = TemplateUtils.GetTemplate("FieldFromParameter"); + var template = TemplateUtils.GetTemplate("FieldFromParameter"); template = TemplateUtils.ReplaceTemplateVariable(template, "Name", scopedVarName); template = TemplateUtils.ReplaceTemplateVariable(template, "Value", paramName); template += "\n$(Boundary)"; - SnippetHelper.InsertSnippetText(sci, funcBodyStart, template); + SnippetHelper.InsertSnippetText(sci, bodyStart, template); - //TODO: We also need to check parent classes!!! - MemberList classMembers = inClass.Members; - foreach (MemberModel classMember in classMembers) - if (classMember.Name.Equals(varName)) - { - ASContext.Panel.RestoreLastLookupPosition(); - return; - } + if (inClass.ContainsMember(varName, true)) + { + ASContext.Panel.RestoreLastLookupPosition(); + return; + } - MemberModel latest = GetLatestMemberForVariable(GeneratorJobType.Variable, inClass, GetDefaultVisibility(inClass), new MemberModel()); - if (latest == null) return; + var latest = GetLatestMemberForVariable(GeneratorJobType.Variable, inClass, GetDefaultVisibility(inClass), new MemberModel()); + if (latest is null) return; - int position = FindNewVarPosition(sci, inClass, latest); + var position = FindNewVarPosition(sci, inClass, latest); if (position <= 0) return; sci.SetSel(position, position); - sci.CurrentPos = position; - MemberModel mem = NewMember(varName, member, FlagType.Variable, scope); - if (isVararg) mem.Type = "Array"; - else mem.Type = paramType; + var newMember = NewMember(varName, member, FlagType.Variable, scope); + newMember.Type = paramType; - GenerateVariable(mem, position, true); + GenerateVariable(newMember, position, true); ASContext.Panel.RestoreLastLookupPosition(); + if (ASContext.Context.Settings.GenerateImports) + { + var imports = new List {paramType}; + var types = GetQualifiedTypes(imports, inClass.InFile); + position += AddImportsByName(types, sci.LineFromPosition(position)); + sci.SetSel(position, position); + } } - /// - /// Tries to get the best position inside a code block, delimited by { and }, to add new code, inserting new lines if needed. - /// - /// The line inside the Scintilla document where the owner member of the body starts - /// The line inside the Scintilla document where the owner member of the body ends - /// The Scintilla control containing the document - /// The position inside the scintilla document, or -1 if not suitable position was found - public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl sci) + protected virtual string GetFieldTypeFromParameter(string paramType, ref string paramName) { - return GetBodyStart(lineFrom, lineTo, sci, true); + //for example: foo(v1:Function/*(v1:Type):void*/) + if ((contextMember.Flags & FlagType.Function) != 0) return ASContext.Context.CodeComplete.ToFunctionDeclarationString(new MemberModel {Parameters = contextMember.Parameters, Type = paramType}); + if (paramName.StartsWithOrdinal("...")) + { + paramName = paramName.TrimStart('.'); + return "Array"; + } + return paramType; } - /// - /// Tries to get the start position of a code block, delimited by { and } - /// - /// The line inside the Scintilla document where the owner member of the body starts - /// The line inside the Scintilla document where the owner member of the body ends - /// The Scintilla control containing the document - /// If true looks for the position to add new code, inserting new lines if needed + /// + /// Tries to get the best position inside a code block, delimited by { and }, to add new code, inserting new lines if needed. + /// + /// The line inside the Scintilla document where the owner member of the body starts + /// The line inside the Scintilla document where the owner member of the body ends + /// The Scintilla control containing the document + /// The position inside the scintilla document, or -1 if not suitable position was found + public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl sci) => GetBodyStart(lineFrom, lineTo, sci, true); + + /// + /// Tries to get the start position of a code block, delimited by { and } + /// + /// The line inside the Scintilla document where the owner member of the body starts + /// The line inside the Scintilla document where the owner member of the body ends + /// The Scintilla control containing the document + /// If true looks for the position to add new code, inserting new lines if needed /// The position inside the Scintilla document, or -1 if not suitable position was found public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl sci, bool needsPointOfInsertion) { int posStart = sci.PositionFromLine(lineFrom); int posEnd = sci.LineEndPosition(lineTo); - - int funcBodyStart = -1; - - int genCount = 0, parCount = 0; - for (int i = posStart; i <= posEnd; i++) - { - char c = (char)sci.CharAt(i); - - if (c == '{') - { - int style = sci.BaseStyleAt(i); + int funcBodyStart = -1; + int genCount = 0, parCount = 0; + for (int i = posStart; i <= posEnd; i++) + { + var c = (char)sci.CharAt(i); + if (c == '{') + { + int style = sci.BaseStyleAt(i); if (ASComplete.IsCommentStyle(style) || ASComplete.IsLiteralStyle(style) || genCount > 0 || parCount > 0) - continue; - funcBodyStart = i; - break; - } - else if (c == '<') - { - int style = sci.BaseStyleAt(i); - if (style == 10) - genCount++; - } - else if (c == '>') - { - int style = sci.BaseStyleAt(i); + continue; + funcBodyStart = i; + break; + } + if (c == '<') + { + int style = sci.BaseStyleAt(i); + if (style == 10) + genCount++; + } + else if (c == '>') + { + int style = sci.BaseStyleAt(i); if (style == 10 && genCount > 0) - genCount--; - } + genCount--; + } else if (c == '(') { int style = sci.BaseStyleAt(i); if (style == 10) parCount++; - } + } else if (c == ')') { int style = sci.BaseStyleAt(i); if (style == 10) parCount--; - } - } - - if (funcBodyStart == -1) + } + } + + if (funcBodyStart == -1) return -1; if (needsPointOfInsertion) - { - int ln = sci.LineFromPosition(funcBodyStart); - + { + int ln = sci.LineFromPosition(funcBodyStart); + funcBodyStart++; return GetOrSetPointOfInsertion(funcBodyStart, posEnd, ln, sci); } @@ -2065,78 +2147,17 @@ public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl sci, b return funcBodyStart + 1; } - public static int GetStartOfStatement(ScintillaControl sci, int statementEnd, ASResult expr) - { - var wordBefore = expr.Context?.WordBefore; - if (expr.Type != null && wordBefore != null && ASContext.Context.Features.OtherOperators.Contains(wordBefore)) return expr.Context.WordBeforePosition; - var line = sci.LineFromPosition(statementEnd); - var text = sci.GetLine(line); - var match = Regex.Match(text, @"[;\s\n\r]*", RegexOptions.RightToLeft); - if (match.Success) statementEnd = sci.PositionFromLine(line) + match.Index; - var result = 0; - var characters = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; - var arrCount = 0; - var parCount = 0; - var genCount = 0; - var braCount = 0; - var dQuotes = 0; - var sQuotes = 0; - var hasDot = false; - var c = ' '; - sci.Colourise(0, -1); - for (var i = statementEnd; i > 0; i--) - { - if (sci.PositionIsOnComment(i - 1)) continue; - var pc = c; - c = (char)sci.CharAt(i - 1); - if (c == ']') arrCount++; - else if (c == '[' && arrCount > 0) arrCount--; - else if (c == ')') parCount++; - else if (c == '(' && parCount > 0) parCount--; - else if (c == '>' && arrCount == 0 && parCount == 0 && braCount == 0) - { - if (i > 1 && (char)sci.CharAt(i - 2) != '-') genCount++; - } - else if (c == '<' && genCount > 0 && arrCount == 0 && parCount == 0 && braCount == 0) genCount--; - else if (c == '}') braCount++; - else if (c == '{' && braCount > 0) braCount--; - else if (c == '\"' && sQuotes == 0) - { - if (i <= 1 || (char) sci.CharAt(i - 2) == '\\') continue; - if (dQuotes == 0) dQuotes++; - else dQuotes--; - if (arrCount == 0 && parCount == 0) hasDot = false; - } - else if (c == '\'' && dQuotes == 0) - { - if (i <= 1 || (char) sci.CharAt(i - 2) == '\\') continue; - if (sQuotes == 0) sQuotes++; - else sQuotes--; - if (arrCount == 0 && parCount == 0) hasDot = false; - } - else if (arrCount == 0 && parCount == 0 && genCount == 0 && braCount == 0 && dQuotes == 0 && sQuotes == 0 && !characters.Contains(c) && c != '.') - { - if (hasDot && c <= ' ') - { - while (i > 0) - { - var nextPos = i - 1; - c = (char) sci.CharAt(nextPos); - if (c > ' ' && !sci.PositionIsOnComment(nextPos)) break; - i = nextPos; - } - i++; - } - else - { - result = i; - break; - } - } - else if (!hasDot && c == '.') hasDot = pc != '<' && parCount == 0; - else if (hasDot && characters.Contains(c)) hasDot = false; + [Obsolete(message: "Please use ASGenerator.GetStartOfStatement(expr) instead of ASGenerator.GetStartOfStatement(sci, statementEnd, expr)")] + public static int GetStartOfStatement(ScintillaControl sci, int statementEnd, ASResult expr) => GetStartOfStatement(expr); + + public static int GetStartOfStatement(ASResult expr) + { + if (expr.Type != null) + { + var wordBefore = expr.Context.WordBefore; + if (!string.IsNullOrEmpty(wordBefore) && ASContext.Context.Features.codeKeywords.Contains(wordBefore)) return expr.Context.WordBeforePosition; } - return expr.Context == null ? result : Math.Min(result, expr.Context.PositionExpression); + return expr.Context.PositionExpression; } /// @@ -2148,112 +2169,112 @@ public static int GetStartOfStatement(ScintillaControl sci, int statementEnd, AS /// The position inside the Scintilla document /// For now internal because for the current use we don't need to detect a lot of cases! use with caution! public static int GetEndOfStatement(int startPos, int endPos, ScintillaControl sci) - { - int groupCount = 0; - int brCount = 0; - int statementEnd = startPos; - sci.Colourise(0, -1); - while (statementEnd < endPos) + { + var groupCount = 0; + var brCount = 0; + var statementEnd = startPos; + while (statementEnd < endPos) { if (sci.PositionIsOnComment(statementEnd) || sci.PositionIsInString(statementEnd)) { statementEnd++; continue; } - char c = (char)sci.CharAt(statementEnd++); - bool endOfStatement = false; - switch (c) - { - case '\r': - case '\n': - endOfStatement = groupCount == 0 && brCount == 0; - break; - case ';': - endOfStatement = brCount == 0; // valid or invalid end of statement - break; - case '(': - case '[': - groupCount++; - break; - case '{': - brCount++; - break; - case ')': - case ']': - groupCount--; - break; - case '}': - brCount--; - break; - } - - if (endOfStatement) break; + var endOfStatement = false; + var c = (char)sci.CharAt(statementEnd++); + switch (c) + { + case '\r': + case '\n': + case ',': + endOfStatement = groupCount == 0 && brCount == 0; + break; + case ';': + endOfStatement = brCount == 0; // valid or invalid end of statement + break; + case '(': + case '[': + groupCount++; + break; + case '{': + brCount++; + break; + case ')': + case ']': + groupCount--; + endOfStatement = groupCount < 0; + break; + case '}': + brCount--; + endOfStatement = brCount < 0; + break; + } + if (endOfStatement) break; } - return statementEnd; } - /// - /// Looks for the best next position to insert new code, inserting new lines if needed - /// - /// The position inside the Scintilla document to start looking for the insertion position - /// The end position inside the Scintilla document - /// The line inside the document to use as the base for the indentation level and detect if the desired point - /// matches the end line - /// The ScintillaControl where our document resides + /// + /// Looks for the best next position to insert new code, inserting new lines if needed + /// + /// The position inside the Scintilla document to start looking for the insertion position + /// The end position inside the Scintilla document + /// The line inside the document to use as the base for the indentation level and detect if the desired point + /// matches the end line + /// The ScintillaControl where our document resides /// The insertion point position - private static int GetOrSetPointOfInsertion(int startPos, int endPos, int baseLine, ScintillaControl sci) + static int GetOrSetPointOfInsertion(int startPos, int endPos, int baseLine, ScintillaControl sci) { - char[] characterClass = { ' ', '\r', '\n', '\t' }; - int nCount = 0; + char[] characterClass = { ' ', '\r', '\n', '\t' }; + int nCount = 0; int extraLine = 1; - int initialLn = sci.LineFromPosition(startPos); - int baseIndent = sci.GetLineIndentation(baseLine); - - bool found = false; - while (startPos <= endPos) - { - char c = (char)sci.CharAt(startPos); - if (Array.IndexOf(characterClass, c) == -1) - { - int endLn = sci.LineFromPosition(startPos); - if (endLn == baseLine || endLn == initialLn) - { - sci.InsertText(startPos, sci.NewLineMarker); - // Do we want to set the line indentation no matter what? {\r\t\t\t\r} -> {\r\t\r} - // Better results in most cases, but maybe highly unwanted in others? - sci.SetLineIndentation(++endLn, baseIndent + sci.Indent); - startPos = sci.LineIndentPosition(endLn); - } - if (c == '}') - { - sci.InsertText(startPos, sci.NewLineMarker); + int initialLn = sci.LineFromPosition(startPos); + int baseIndent = sci.GetLineIndentation(baseLine); + + bool found = false; + while (startPos <= endPos) + { + char c = (char)sci.CharAt(startPos); + if (!characterClass.Contains(c)) + { + int endLn = sci.LineFromPosition(startPos); + if (endLn == baseLine || endLn == initialLn) + { + sci.InsertText(startPos, sci.NewLineMarker); + // Do we want to set the line indentation no matter what? {\r\t\t\t\r} -> {\r\t\r} + // Better results in most cases, but maybe highly unwanted in others? + sci.SetLineIndentation(++endLn, baseIndent + sci.Indent); + startPos = sci.LineIndentPosition(endLn); + } + if (c == '}') + { + sci.InsertText(startPos, sci.NewLineMarker); sci.SetLineIndentation(endLn + 1, baseIndent); // In relation with previous comment... we'll reinden this one: {\r} -> {\r\t\r} if (sci.GetLineIndentation(endLn) <= baseIndent) { - sci.SetLineIndentation(endLn, baseIndent + sci.Indent); - startPos = sci.LineIndentPosition(endLn); - } - } - found = true; - break; - } - else if (sci.EOLMode == 1 && c == '\r' && (++nCount) > extraLine) - { - found = true; - break; - } - else if (c == '\n' && (++nCount) > extraLine) - { - if (sci.EOLMode != 2) - { - startPos--; - } - found = true; - break; - } + sci.SetLineIndentation(endLn, baseIndent + sci.Indent); + startPos = sci.LineIndentPosition(endLn); + } + } + found = true; + break; + } + if (sci.EOLMode == 1 && c == '\r' && (++nCount) > extraLine) + { + found = true; + break; + } + if (c == '\n' && (++nCount) > extraLine) + { + if (sci.EOLMode != 2) + { + startPos--; + } + found = true; + break; + } startPos++; } @@ -2262,47 +2283,32 @@ private static int GetOrSetPointOfInsertion(int startPos, int endPos, int baseLi return startPos; } - private static void GenerateToString(ScintillaControl sci, ClassModel inClass) + static void GenerateToString(ScintillaControl sci, ClassModel inClass) { - MemberModel resultMember = new MemberModel("toString", ASContext.Context.Features.stringKey, FlagType.Function, Visibility.Public); - - bool isOverride = false; + var resultMember = new MemberModel("toString", ASContext.Context.Features.stringKey, FlagType.Function, Visibility.Public); inClass.ResolveExtends(); - if (inClass.Extends != null) + var extends = inClass.Extends; + while (!extends.IsVoid() && extends.QualifiedName != "Object") { - ClassModel aType = inClass.Extends; - while (!aType.IsVoid() && aType.QualifiedName != "Object") + if (extends.Members.Contains("toString")) { - foreach (MemberModel method in aType.Members) - { - if (method.Name == "toString") - { - isOverride = true; - break; - } - } - if (isOverride) - { - resultMember.Flags |= FlagType.Override; - break; - } - // interface inheritance - aType = aType.Extends; + resultMember.Flags |= FlagType.Override; + break; } + extends = extends.Extends; } - MemberList members = inClass.Members; - StringBuilder membersString = new StringBuilder(); - int len = 0; - foreach (MemberModel m in members) + var membersString = new StringBuilder(); + var len = 0; + foreach (var m in inClass.Members) { if (((m.Flags & FlagType.Variable) > 0 || (m.Flags & FlagType.Getter) > 0) && (m.Access & Visibility.Public) > 0 && (m.Flags & FlagType.Constant) == 0) { - var oneMembersString = new StringBuilder(); - oneMembersString.Append(" ").Append(m.Name).Append("=\" + ").Append(m.Name).Append(" + "); - membersString.Append(oneMembersString); - len += oneMembersString.Length; + var sb = new StringBuilder(); + sb.Append(" ").Append(m.Name).Append("=\" + ").Append(m.Name).Append(" + "); + membersString.Append(sb); + len += sb.Length; if (len > 80) { len = 0; @@ -2311,30 +2317,26 @@ private static void GenerateToString(ScintillaControl sci, ClassModel inClass) membersString.Append("\""); } } - - - string template = TemplateUtils.GetTemplate("ToString"); - string result = TemplateUtils.ToDeclarationWithModifiersString(resultMember, template); + var template = TemplateUtils.GetTemplate("ToString"); + var result = ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(resultMember, template); result = TemplateUtils.ReplaceTemplateVariable(result, "Body", "\"[" + inClass.Name + membersString + "]\""); - InsertCode(sci.CurrentPos, result, sci); } - private static void GenerateVariableJob(GeneratorJobType job, ScintillaControl sci, MemberModel member, bool detach, ClassModel inClass) + static void GenerateVariableJob(GeneratorJobType job, ScintillaControl sci, MemberModel member, bool detach, ClassModel inClass) { var wordStartPos = sci.WordStartPosition(sci.CurrentPos, true); - var position = 0; - Visibility visibility = job.Equals(GeneratorJobType.Variable) ? GetDefaultVisibility(inClass) : Visibility.Public; + var visibility = job.Equals(GeneratorJobType.Variable) ? GetDefaultVisibility(inClass) : Visibility.Public; // evaluate, if the variable (or constant) should be generated in other class - ASResult varResult = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); + var varResult = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); if (member != null && ASContext.CommonSettings.GenerateScope && !varResult.Context.Value.Contains(ASContext.Context.Features.dot)) AddExplicitScopeReference(sci, inClass, member); - int contextOwnerPos = GetContextOwnerEndPos(sci, sci.WordStartPosition(sci.CurrentPos, true)); - MemberModel isStatic = new MemberModel(); + var contextOwnerPos = GetContextOwnerEndPos(sci, sci.WordStartPosition(sci.CurrentPos, true)); + var isStatic = new MemberModel(); if (contextOwnerPos != -1) { - ASResult contextOwnerResult = ASComplete.GetExpressionType(sci, contextOwnerPos); + var contextOwnerResult = ASComplete.GetExpressionType(sci, contextOwnerPos); if (contextOwnerResult != null - && (contextOwnerResult.Member == null || (contextOwnerResult.Member.Flags & FlagType.Constructor) > 0) + && (contextOwnerResult.Member is null || (contextOwnerResult.Member.Flags & FlagType.Constructor) > 0) && contextOwnerResult.Type != null) { isStatic.Flags |= FlagType.Static; @@ -2345,65 +2347,54 @@ private static void GenerateVariableJob(GeneratorJobType job, ScintillaControl s isStatic.Flags |= FlagType.Static; } - ASResult returnType = null; - int lineNum = sci.CurrentLine; - string line = sci.GetLine(lineNum); + ASResult returnType = null; + var lineNum = sci.CurrentLine; + var line = sci.GetLine(lineNum); - Match m = Regex.Match(line, "\\b" + Regex.Escape(contextToken) + "\\("); - if (m.Success) + if (Regex.IsMatch(line, "\\b" + Regex.Escape(contextToken) + "\\(")) { - returnType = new ASResult(); - returnType.Type = ASContext.Context.ResolveType("Function", null); + returnType = new ASResult {Type = ASContext.Context.ResolveType("Function", null)}; } else { - m = Regex.Match(line, @"=\s*[^;\n\r}}]+"); - if (m.Success) + for (int i = sci.WordEndPosition(sci.CurrentPos, true), length = sci.Length; i < length; i++) { - int posLineStart = sci.PositionFromLine(lineNum); - if (posLineStart + m.Index >= sci.CurrentPos) + if (sci.PositionIsOnComment(i)) continue; + var c = sci.CharAt(i); + if (c <= ' ') continue; + if (c == '=') { - line = line.Substring(m.Index); - StatementReturnType rType = GetStatementReturnType(sci, inClass, line, posLineStart + m.Index); - if (rType != null) - { - returnType = rType.resolve; - } + i = GetEndOfStatement(i, sci.Length, sci) - 1; + returnType = ASComplete.GetExpressionType(sci, i, false, true); } + break; } } - bool isOtherClass = false; + var isOtherClass = false; if (varResult.RelClass != null && !varResult.RelClass.IsVoid() && !varResult.RelClass.Equals(inClass)) { AddLookupPosition(); lookupPosition = -1; - - ASContext.MainForm.OpenEditableDocument(varResult.RelClass.InFile.FileName, false); - sci = ASContext.CurSciControl; - isOtherClass = true; - - FileModel fileModel = new FileModel(); - fileModel.Context = ASContext.Context; - ASFileParser parser = new ASFileParser(); - parser.ParseSrc(fileModel, sci.Text); - - foreach (ClassModel cm in fileModel.Classes) + sci = ((ITabbedDocument)PluginBase.MainForm.OpenEditableDocument(varResult.RelClass.InFile.FileName, false))?.SciControl; + if (sci is null) return; + var fileModel = ASContext.Context.GetCodeModel(sci.Text); + foreach (var cm in fileModel.Classes) { - if (cm.QualifiedName.Equals(varResult.RelClass.QualifiedName)) - { - varResult.RelClass = cm; - break; - } + if (!cm.QualifiedName.Equals(varResult.RelClass.QualifiedName)) continue; + varResult.RelClass = cm; + break; } inClass = varResult.RelClass; - ASContext.Context.UpdateContext(inClass.LineFrom); + isOtherClass = true; } var latest = GetLatestMemberForVariable(job, inClass, visibility, isStatic); - + int position; // if we generate variable in current class.. - if (!isOtherClass && member == null) + if (!isOtherClass && (member is null + // TODO slavara: temporary solution for #2477 + || (member.Name is null && member.Type is null && member.Access == 0 && member.Flags == FlagType.Static))) { detach = false; lookupPosition = -1; @@ -2427,39 +2418,40 @@ private static void GenerateVariableJob(GeneratorJobType job, ScintillaControl s // if this is a constant, we assign a value to constant string returnTypeStr = null; - if (job == GeneratorJobType.Constant && returnType == null) - { - isStatic.Flags |= FlagType.Static; - } + if (job == GeneratorJobType.Constant && returnType is null) isStatic.Flags |= FlagType.Static; else if (returnType != null) { - ClassModel inClassForImport; - if (returnType.InClass != null) inClassForImport = returnType.InClass; - else if (returnType.RelClass != null) inClassForImport = returnType.RelClass; - else inClassForImport = inClass; - List imports = new List(1); if (returnType.Member != null) { - if (returnType.Member.Type != ASContext.Context.Features.voidKey) - { + if ((returnType.Member.Flags & FlagType.Function) != 0 && returnType.Context.Value[returnType.Context.Value.Length - 1] != '~') + returnTypeStr = ASContext.Context.CodeComplete.ToFunctionDeclarationString(returnType.Member); + else if (returnType.Member.Type != ASContext.Context.Features.voidKey) returnTypeStr = returnType.Member.Type; - imports.Add(returnType.Member.Type); - } - } - else if (returnType.Type != null) - { - returnTypeStr = returnType.Type.QualifiedName; - imports.Add(returnType.Type.QualifiedName); } - if (ASContext.Context.Settings.GenerateImports && imports.Count > 0) + else if (returnType.Type != null) returnTypeStr = GetShortType(returnType.Type.QualifiedName); + if (ASContext.Context.Settings.GenerateImports) { - var types = GetQualifiedTypes(imports, inClassForImport.InFile); - position += AddImportsByName(types, sci.LineFromPosition(position)); - sci.SetSel(position, position); + ClassModel inClassForImport; + if (returnType.InClass != null) inClassForImport = returnType.InClass; + else if (returnType.RelClass != null) inClassForImport = returnType.RelClass; + else inClassForImport = inClass; + List imports = null; + if (returnType.Member != null) + { + if (returnTypeStr != ASContext.Context.Features.voidKey) imports = new List {returnTypeStr}; + } + else if (returnType.Type != null) imports = new List {returnType.Type.QualifiedName}; + if (imports != null) + { + var types = GetQualifiedTypes(imports, inClassForImport.InFile); + position += AddImportsByName(types, sci.LineFromPosition(position)); + sci.SetSel(position, position); + } } - } - FlagType kind = job.Equals(GeneratorJobType.Constant) ? FlagType.Constant : FlagType.Variable; - MemberModel newMember = NewMember(contextToken, isStatic, kind, visibility); + } + + var kind = job.Equals(GeneratorJobType.Constant) ? FlagType.Constant : FlagType.Variable; + var newMember = NewMember(contextToken, isStatic, kind, visibility); if (returnTypeStr != null) newMember.Type = returnTypeStr; else { @@ -2471,7 +2463,7 @@ private static void GenerateVariableJob(GeneratorJobType job, ScintillaControl s if (expr?.Member?.Parameters.Count > 0) newMember.Type = expr.Member.Parameters[index].Type; } } - if (job == GeneratorJobType.Constant && returnType == null) + if (job == GeneratorJobType.Constant && returnType is null) { if (string.IsNullOrEmpty(newMember.Type)) newMember.Type = "String = \"" + Camelize(contextToken) + "\""; else @@ -2483,35 +2475,31 @@ private static void GenerateVariableJob(GeneratorJobType job, ScintillaControl s GenerateVariable(newMember, position, detach); } - private static int GetContextOwnerEndPos(ScintillaControl sci, int wordStartPos) + static int GetContextOwnerEndPos(ScintillaControl sci, int wordStartPos) { - int pos = wordStartPos - 1; - bool dotFound = false; - while (pos > 0) + var result = wordStartPos - 1; + var dotFound = false; + while (result > 0) { - char c = (char) sci.CharAt(pos); + var c = (char) sci.CharAt(result); if (c == '.' && !dotFound) dotFound = true; else if (c == '\t' || c == '\n' || c == '\r' || c == ' ') { /* skip */ } - else return dotFound ? pos + 1 : -1; - pos--; + else return dotFound ? result + 1 : -1; + result--; } - return pos; + return result; } - public static string Capitalize(string name) - { - return !string.IsNullOrEmpty(name) ? Char.ToUpper(name[0]) + name.Substring(1) : name; - } + public static string Capitalize(string name) => !string.IsNullOrEmpty(name) ? char.ToUpper(name[0]) + name.Substring(1) : name; public static string Camelize(string name) { - name = name.Trim(new char[] { '\'', '"' }); - string[] parts = name.ToLower().Split('_'); - string result = ""; - foreach (string part in parts) + name = name.Trim('\'', '"'); + var parts = name.ToLower().Split('_'); + var result = ""; + foreach (var part in parts) { - if (result.Length > 0) - result += Capitalize(part); + if (result.Length > 0) result += Capitalize(part); else result = part; } return result; @@ -2519,275 +2507,128 @@ public static string Camelize(string name) public static List ParseFunctionParameters(ScintillaControl sci, int p) { - List prms = new List(); - StringBuilder sb = new StringBuilder(); - List types = new List(); - bool isFuncStarted = false; - bool isDoubleQuote = false; - bool isSingleQuote = false; - bool wasEscapeChar = false; - bool doBreak = false; - bool writeParam = false; - int subClosuresCount = 0; + var prms = new List(); + var sb = new StringBuilder(); + var types = new List(); + var isFuncStarted = false; + var doBreak = false; + var writeParam = false; + var subClosuresCount = 0; var arrCount = 0; - IASContext ctx = ASContext.Context; + var ctx = ASContext.Context; char[] charsToTrim = {' ', '\t', '\r', '\n'}; - int counter = sci.TextLength; // max number of chars in parameters line (to avoid infinitive loop) - string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; - int lastMemberPos = p; + var counter = sci.TextLength; // max number of chars in parameters line (to avoid infinitive loop) + var characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; - char c = ' '; - // add [] and <> while (p < counter && !doBreak) { - var c2 = c; - c = (char)sci.CharAt(p++); - ASResult result; + if (sci.PositionIsOnComment(p)) + { + p++; + continue; + } + if (sci.PositionIsInString(p)) + { + sb.Append((char)sci.CharAt(p++)); + continue; + } + var c = (char) sci.CharAt(p++); if (c == '(' && !isFuncStarted) { - if (sb.ToString().Trim(charsToTrim).Length == 0) - { - isFuncStarted = true; - } - else - { - break; - } + if (sb.ToString().Trim(charsToTrim).Length == 0) isFuncStarted = true; + else break; } else if (c == ';' && !isFuncStarted) break; - else if (c == ')' && isFuncStarted && !wasEscapeChar && !isDoubleQuote && !isSingleQuote && subClosuresCount == 0) + else if (c == ')' && isFuncStarted && subClosuresCount == 0) { isFuncStarted = false; writeParam = true; doBreak = true; } - else if ((c == '(' || c == '[' || c == '<' || c == '{') && !wasEscapeChar && !isDoubleQuote && !isSingleQuote) + else if (c == '(' || c == '[' || c == '{') { if (c == '[') arrCount++; - if (subClosuresCount == 0) - { - if (c == '(') - { - if (!sb.ToString().Contains("<") && !isFuncStarted) - { - result = ASComplete.GetExpressionType(sci, lastMemberPos + 1); - if (!result.IsNull()) - { - types.Insert(0, result); - } - } - } - else if (c == '<') - { - if (sb.ToString().TrimStart().Length == 0) - { - result = new ASResult(); - result.Type = ctx.ResolveType("XML", null); - types.Insert(0, result); - } - } - } subClosuresCount++; sb.Append(c); - wasEscapeChar = false; } - else if ((c == ')' || c == ']' || (c2 != '-' && c == '>') || c == '}') && !wasEscapeChar && !isDoubleQuote && !isSingleQuote) + else if (c == ')' || c == ']' || c == '}') { if (c == ']') arrCount--; subClosuresCount--; sb.Append(c); - wasEscapeChar = false; if (subClosuresCount == 0) { - if (c == ']') + if (c == ']' && arrCount == 0) { - if (arrCount == 0) + var cNext = sci.CharAt(p); + if (cNext != '[' && cNext != '.' && cNext != '(') { - var cNext = sci.CharAt(p); - if (cNext != '[' && cNext != '.') + if (!sb.ToString().Contains("<")) { - if (!sb.ToString().Contains("<")) - { - result = ASComplete.GetExpressionType(sci, p); - if (result.Type != null) result.Member = null; - else result.Type = ctx.ResolveType(ctx.Features.arrayKey, null); - types.Insert(0, result); - } - writeParam = true; + var result = ASComplete.GetExpressionType(sci, p); + if (result.Type != null) result.Member = null; + else result.Type = ctx.ResolveType(ctx.Features.arrayKey, null); + types.Insert(0, result); } } } - else if (c == ')' && sb.ToString().StartsWithOrdinal("new")) - { - lastMemberPos = p - 1; - writeParam = true; - } - else if (c == '}') - { - var s = sb.ToString().TrimStart(); - if (s.Length > 0 && s.StartsWith("function")) - { - result = new ASResult(); - result.Type = ctx.ResolveType("Function", null); - types.Insert(0, result); - } - else types.Insert(0, ASComplete.GetExpressionType(sci, p)); - } - } - } - else if (c == '\\') - { - wasEscapeChar = !wasEscapeChar; - sb.Append(c); - } - else if (c == '"' && !wasEscapeChar && !isSingleQuote) - { - isDoubleQuote = !isDoubleQuote; - if (subClosuresCount == 0 && !isDoubleQuote && (char) sci.CharAt(p) != '.') - { - result = ASComplete.GetExpressionType(sci, p); - types.Add(result); - } - sb.Append(c); - wasEscapeChar = false; - } - else if (c == '\'' && !wasEscapeChar && !isDoubleQuote) - { - isSingleQuote = !isSingleQuote; - if (subClosuresCount == 0 && !isSingleQuote) - { - result = ASComplete.GetExpressionType(sci, p); - types.Add(result); - } - sb.Append(c); - wasEscapeChar = false; - } - else if (c == ',' && subClosuresCount == 0 && !isDoubleQuote && !isSingleQuote) - { - if (isFuncStarted) - { - result = ASComplete.GetExpressionType(sci, p - 1, true, true); - result.Context.coma = ComaExpression.FunctionParameter; - types.Add(result); - writeParam = true; - } - else if (!isSingleQuote && !isDoubleQuote) - { - writeParam = true; - } - else - { - sb.Append(c); - } - wasEscapeChar = false; - } - else if (isFuncStarted) - { - sb.Append(c); - if (!isSingleQuote && !isDoubleQuote && subClosuresCount == 0 && characterClass.IndexOf(c) > -1) - { - lastMemberPos = p - 1; } - wasEscapeChar = false; - } - else if (characterClass.IndexOf(c) > -1) - { - if (!isDoubleQuote && !isSingleQuote) doBreak = true; - else sb.Append(c); } + else if (c == ',' && subClosuresCount == 0) writeParam = true; + else if (isFuncStarted) sb.Append(c); + else if (characterClass.Contains(c)) doBreak = true; if (writeParam) { writeParam = false; - string trimmed = sb.ToString().Trim(charsToTrim); - if (trimmed.Length > 0) + var trimmed = sb.ToString().Trim(charsToTrim); + var trimmedLength = trimmed.Length; + if (trimmedLength > 0) { - if (trimmed.Contains("<")) - { - var expr = trimmed.StartsWithOrdinal("new") - ? ASComplete.GetExpressionType(sci, lastMemberPos + 1, true, true).Context - : null; - trimmed = Regex.Replace(trimmed, @"^new\s", string.Empty); - trimmed = Regex.Replace(trimmed, @">\(.*", ">"); - var type = ctx.ResolveType(trimmed, ctx.CurrentModel); - result = new ASResult {Type = type, Context = expr}; - } - else if (trimmed.StartsWithOrdinal("new")) result = ASComplete.GetExpressionType(sci, lastMemberPos + 1, true, true); - else result = ASComplete.GetExpressionType(sci, lastMemberPos + 1); + var last = trimmed[trimmedLength - 1]; + var type = last == '}' && trimmed.StartsWith(ctx.Features.functionKey) + ? ctx.ResolveType("Function", null) + : ctx.ResolveToken(trimmed, ctx.CurrentModel); + var result = type.IsVoid() + ? ASComplete.GetExpressionType(sci, p - 1, false, true) + : new ASResult {Type = type, Context = new ASExpr {Value = trimmed}}; if (result != null && !result.IsNull()) { - if (characterClass.IndexOf(trimmed[trimmed.Length - 1]) > -1) - { - types.Insert(0, result); - } - else - { - types.Add(result); - } - } - else - { - double d = double.MaxValue; - try - { - d = double.Parse(trimmed, CultureInfo.InvariantCulture); - } - catch (Exception) - { - } - if (d != double.MaxValue && d.ToString().Length == trimmed.Length) - { - result = new ASResult(); - result.Type = ctx.ResolveType(ctx.Features.numberKey, null); - types.Insert(0, result); - } - else if (trimmed.Equals("true") || trimmed.Equals("false")) - { - result = new ASResult(); - result.Type = ctx.ResolveType(ctx.Features.booleanKey, null); - types.Insert(0, result); - } - } - - if (types.Count == 0) - { - result = new ASResult(); - result.Type = ctx.ResolveType(ctx.Features.objectKey, null); - types.Add(result); + if (characterClass.Contains(last)) types.Insert(0, result); + else types.Add(result); } + if (types.Count == 0) types.Add(new ASResult {Type = ctx.ResolveType(ctx.Features.objectKey, null)}); result = types[0]; string paramName = null; - string paramType = null; - string paramQualType = null; + string paramType; + string paramQualType; - if (result.Member == null) + if (result.Member is null) { paramType = result.Type.Name; paramQualType = result.Type.QualifiedName; } else { - if (result.Member.Name != null) - { - paramName = result.Member.Name.Trim('@'); - } - if (result.Member.Type == null) + if (result.Member.Name != null) paramName = result.Member.Name.Trim('@'); + if (result.Member.Type is null) { paramType = ctx.Features.dynamicKey; paramQualType = ctx.Features.dynamicKey; } else { - paramType = FormatType(GetShortType(result.Member.Type)); - if (result.InClass == null) + var flags = result.Member.Flags; + if ((flags & FlagType.Function) != 0 && (flags & FlagType.Getter) == 0 && (flags & FlagType.Setter) == 0 + && !result.Path.EndsWith('~')) { - paramQualType = result.Type.QualifiedName; - } - else - { - paramQualType = GetQualifiedType(result.Member.Type, result.InClass); + paramType = ctx.CodeComplete.ToFunctionDeclarationString(result.Member); } + else paramType = MemberModel.FormatType(GetShortType(result.Member.Type)); + paramQualType = result.InClass is null + ? result.Type.QualifiedName + : GetQualifiedType(paramType, result.InClass); } } prms.Add(new FunctionParameter(paramName, paramType, paramQualType, result)); @@ -2796,17 +2637,15 @@ public static List ParseFunctionParameters(ScintillaControl s sb = new StringBuilder(); } } - - for (int i = 0; i < prms.Count; i++) + foreach (var parameter in prms) { - if (prms[i].paramType == "void") + if (parameter.paramType == "void") { - prms[i].paramName = "object"; - prms[i].paramType = null; + parameter.paramName = "object"; + parameter.paramType = null; } - else prms[i].paramName = GuessVarName(prms[i].paramName, FormatType(GetShortType(prms[i].paramType))); + else parameter.paramName = GuessVarName(parameter.paramName, MemberModel.FormatType(GetShortType(parameter.paramType))); } - for (int i = 0; i < prms.Count; i++) { int iterator = -1; @@ -2835,65 +2674,65 @@ public static List ParseFunctionParameters(ScintillaControl s static void GenerateConstructorJob(ScintillaControl sci, ClassModel inClass) { - var position = sci.WordEndPosition(sci.CurrentPos, true); - var parameters = ParseFunctionParameters(sci, position); - var member = new MemberModel(inClass.Name, inClass.QualifiedName, FlagType.Constructor | FlagType.Function, Visibility.Public) - { - Parameters = parameters.Select(it => new MemberModel(it.paramName, it.paramQualType, FlagType.ParameterVar, 0)).ToList() + const FlagType flags = FlagType.Function | FlagType.Constructor; + var member = new MemberModel(inClass.Name, inClass.QualifiedName, flags, Visibility.Public) + { + Parameters = inClass.SearchMembers(flags, true)?[0].Parameters + // for example: new Type(value); + ?? ParseFunctionParameters(sci, sci.WordEndPosition(sci.CurrentPos, true)) + .Select(static it => new MemberModel(it.paramName, it.paramQualType, FlagType.ParameterVar, 0)) + .ToList() }; var currentClass = ASContext.Context.CurrentClass; if (currentClass != inClass) { AddLookupPosition(); lookupPosition = -1; - if (currentClass.InFile != inClass.InFile) sci = ((ITabbedDocument)PluginBase.MainForm.OpenEditableDocument(inClass.InFile.FileName, false)).SciControl; + if (currentClass.InFile != inClass.InFile) sci = ((ITabbedDocument)PluginBase.MainForm.OpenEditableDocument(inClass.InFile.FileName, false))?.SciControl; + if (sci is null) return; ASContext.Context.UpdateContext(inClass.LineFrom); } - position = GetBodyStart(inClass.LineFrom, inClass.LineTo, sci); + var position = GetBodyStart(inClass.LineFrom, inClass.LineTo, sci); sci.SetSel(position, position); - GenerateFunction(member, position, inClass, false); + ((ASGenerator) ASContext.Context.CodeGenerator).GenerateFunction(sci, position, inClass, member, false); } - private static void GenerateFunctionJob(GeneratorJobType job, ScintillaControl sci, MemberModel member, bool detach, ClassModel inClass) + static void GenerateFunctionJob(GeneratorJobType job, ScintillaControl sci, MemberModel member, bool detach, ClassModel inClass) { - Visibility visibility = job.Equals(GeneratorJobType.FunctionPublic) ? Visibility.Public : GetDefaultVisibility(inClass); + var visibility = job.Equals(GeneratorJobType.FunctionPublic) ? Visibility.Public : GetDefaultVisibility(inClass); var wordStartPos = sci.WordStartPosition(sci.CurrentPos, true); - int wordPos = sci.WordEndPosition(sci.CurrentPos, true); - List functionParameters = ParseFunctionParameters(sci, wordPos); + var wordPos = sci.WordEndPosition(sci.CurrentPos, true); + var parameters = ParseFunctionParameters(sci, wordPos); // evaluate, if the function should be generated in other class - ASResult funcResult = ASComplete.GetExpressionType(sci, sci.WordEndPosition(sci.CurrentPos, true)); + var funcResult = ASComplete.GetExpressionType(sci, wordPos); if (member != null && ASContext.CommonSettings.GenerateScope && !funcResult.Context.Value.Contains(ASContext.Context.Features.dot)) AddExplicitScopeReference(sci, inClass, member); - int contextOwnerPos = GetContextOwnerEndPos(sci, sci.WordStartPosition(sci.CurrentPos, true)); - MemberModel isStatic = new MemberModel(); + var contextOwnerPos = GetContextOwnerEndPos(sci, wordStartPos); + var isStatic = new MemberModel(); if (contextOwnerPos != -1) { var contextOwnerResult = ASComplete.GetExpressionType(sci, contextOwnerPos); - if (contextOwnerResult != null - && (contextOwnerResult.Member == null || (contextOwnerResult.Member.Flags & FlagType.Constructor) > 0) - && contextOwnerResult.Type != null) + if (contextOwnerResult is not null + && (contextOwnerResult.Member is null || (contextOwnerResult.Member.Flags & FlagType.Constructor) > 0) + && contextOwnerResult.Type is not null) { isStatic.Flags |= FlagType.Static; } } - else if (member != null && (member.Flags & FlagType.Static) > 0) + else if (member is not null && (member.Flags & FlagType.Static) > 0) { isStatic.Flags |= FlagType.Static; } - bool isOtherClass = false; - if (funcResult.RelClass != null && !funcResult.RelClass.IsVoid() && !funcResult.RelClass.Equals(inClass)) + var isOtherClass = false; + if (funcResult.RelClass is not null && !funcResult.RelClass.IsVoid() && !funcResult.RelClass.Equals(inClass)) { AddLookupPosition(); lookupPosition = -1; - ASContext.MainForm.OpenEditableDocument(funcResult.RelClass.InFile.FileName, true); - sci = ASContext.CurSciControl; + sci = ((ITabbedDocument)PluginBase.MainForm.OpenEditableDocument(funcResult.RelClass.InFile.FileName, true))?.SciControl; + if (sci is null) return; isOtherClass = true; - - var fileModel = new FileModel {Context = ASContext.Context}; - var parser = new ASFileParser(); - parser.ParseSrc(fileModel, sci.Text); - - foreach (ClassModel cm in fileModel.Classes) + var fileModel = ASContext.Context.GetCodeModel(sci.Text); + foreach (var cm in fileModel.Classes) { if (cm.QualifiedName.Equals(funcResult.RelClass.QualifiedName)) { @@ -2902,40 +2741,31 @@ private static void GenerateFunctionJob(GeneratorJobType job, ScintillaControl s } } inClass = funcResult.RelClass; - ASContext.Context.UpdateContext(inClass.LineFrom); } string blockTmpl; - if ((isStatic.Flags & FlagType.Static) > 0) - { - blockTmpl = TemplateUtils.GetBoundary("StaticMethods"); - } - else if ((visibility & Visibility.Public) > 0) - { - blockTmpl = TemplateUtils.GetBoundary("PublicMethods"); - } - else - { - blockTmpl = TemplateUtils.GetBoundary("PrivateMethods"); - } + if ((isStatic.Flags & FlagType.Static) > 0) blockTmpl = TemplateUtils.GetBoundary("StaticMethods"); + else if ((visibility & Visibility.Public) > 0) blockTmpl = TemplateUtils.GetBoundary("PublicMethods"); + else blockTmpl = TemplateUtils.GetBoundary("PrivateMethods"); + var position = 0; var latest = TemplateUtils.GetTemplateBlockMember(sci, blockTmpl); - if (latest == null || (!isOtherClass && member == null)) + if (latest is null || (!isOtherClass && member is null)) { latest = GetLatestMemberForFunction(inClass, visibility, isStatic); // if we generate function in current class.. if (!isOtherClass) { var location = ASContext.CommonSettings.MethodsGenerationLocations; - if (member == null) + if (member is null) { detach = false; lookupPosition = -1; position = sci.WordStartPosition(sci.CurrentPos, true); sci.SetSel(position, sci.WordEndPosition(position, true)); } - else if (latest != null && location == MethodsGenerationLocations.AfterSimilarAccessorMethod) + else if (latest is not null && location == MethodsGenerationLocations.AfterSimilarAccessorMethod) { position = sci.PositionFromLine(latest.LineTo + 1) - (sci.EOLMode == 0 ? 2 : 1); sci.SetSel(position, position); @@ -2948,7 +2778,7 @@ private static void GenerateFunctionJob(GeneratorJobType job, ScintillaControl s } else // if we generate function in another class.. { - if (latest != null) + if (latest is not null) { position = sci.PositionFromLine(latest.LineTo + 1) - (sci.EOLMode == 0 ? 2 : 1); } @@ -2965,7 +2795,7 @@ private static void GenerateFunctionJob(GeneratorJobType job, ScintillaControl s position = sci.PositionFromLine(latest.LineTo + 1) - (sci.EOLMode == 0 ? 2 : 1); sci.SetSel(position, position); } - string newMemberType = null; + var newMemberType = ASContext.Context.Features.voidKey; ASResult callerExpr = null; MemberModel caller = null; var pos = wordStartPos; @@ -2973,275 +2803,180 @@ private static void GenerateFunctionJob(GeneratorJobType job, ScintillaControl s if (pos != -1) { callerExpr = ASComplete.GetExpressionType(sci, pos); - if (callerExpr != null) caller = callerExpr.Member; + if (callerExpr is not null) caller = callerExpr.Member; } - if (caller?.Parameters != null && caller.Parameters.Count > 0) + if (caller is not null && !caller.Parameters.IsNullOrEmpty()) { - Func cleanType = null; - cleanType = s => s.StartsWith("(") && s.EndsWith(')') ? cleanType(s.Trim('(', ')')) : s; - var parameterType = caller.Parameters[parameterIndex].Type; - if ((char) sci.CharAt(wordPos) == '(') newMemberType = parameterType; - else + static string CleanType(string s) { - var isNativeFunctionType = false; - if (parameterType == "Function") + while (true) { - if (IsHaxe) + if (s.StartsWith('(') && s.EndsWith(')')) { - var paramType = ASContext.Context.ResolveType(parameterType, callerExpr.InFile); - if (paramType.InFile.Package == "haxe" && paramType.InFile.Module == "Constraints") - isNativeFunctionType = true; + s = s.Trim('(', ')'); + continue; } - else isNativeFunctionType = true; + return s; } - var voidKey = ASContext.Context.Features.voidKey; - if (isNativeFunctionType) newMemberType = voidKey; - else + } + + var param = caller.Parameters[parameterIndex]; + var parameterType = param.Type; + if ((char) sci.CharAt(wordPos) == '(') newMemberType = parameterType; + else + { + var model = ASContext.Context.CodeComplete.FunctionTypeToMemberModel(parameterType, callerExpr.InFile); + if (model != null) { - var parCount = 0; - var braCount = 0; - var genCount = 0; - var startPosition = 0; - var typeLength = parameterType.Length; - for (var i = 0; i < typeLength; i++) + newMemberType = model.Type; + if (model.Parameters != null) { - string type = null; - var c = parameterType[i]; - if (c == '(') parCount++; - else if (c == ')') - { - parCount--; - if (parCount == 0 && braCount == 0 && genCount == 0) - { - type = parameterType.Substring(startPosition, (i + 1) - startPosition); - startPosition = i + 1; - } - } - else if (c == '{') braCount++; - else if (c == '}') - { - braCount--; - if (parCount == 0 && braCount == 0 && genCount == 0) - { - type = parameterType.Substring(startPosition, (i + 1) - startPosition); - startPosition = i + 1; - } - } - else if (c == '<') genCount++; - else if (c == '>' && parameterType[i - 1] != '-') - { - genCount--; - if (parCount == 0 && braCount == 0 && genCount == 0) - { - type = parameterType.Substring(startPosition, (i + 1) - startPosition); - startPosition = i + 1; - } - } - else if (parCount == 0 && braCount == 0 && genCount == 0 && c == '-' && - parameterType[i + 1] == '>') - { - if (i > startPosition) type = parameterType.Substring(startPosition, i - startPosition); - startPosition = i + 2; - i++; - } - if (type == null) - { - if (i == typeLength - 1 && i > startPosition) - newMemberType = parameterType.Substring(startPosition); - continue; - } - type = cleanType(type); - var parameter = $"parameter{functionParameters.Count}"; - if (type.StartsWith('?')) + foreach (var it in model.Parameters) { - parameter = $"?{parameter}"; - type = type.TrimStart('?'); + var type = CleanType(it.Type); + parameters.Add(new FunctionParameter(it.Name, type, type, null)); } - if (i == typeLength - 1) newMemberType = type; - else functionParameters.Add(new FunctionParameter(parameter, type, type, callerExpr)); } - if (functionParameters.Count == 1 && functionParameters[0].paramType == voidKey) - functionParameters.Clear(); } } - newMemberType = cleanType(newMemberType); + newMemberType = CleanType(newMemberType); + // for example: + // foo(v1) + // function foo(v1:Function/*(v1:Type):void*/) + if ((param.Flags & FlagType.Function) != 0 && parameters.Count != param.Parameters.Count) + { + parameters.Clear(); + parameters.AddRange(param.Parameters.Select(static it => new FunctionParameter(it.Name, it.Type, it.Type, null))); + } } // add imports to function argument types - if (ASContext.Context.Settings.GenerateImports && functionParameters.Count > 0) + if (ASContext.Context.Settings.GenerateImports && parameters.Count > 0) { - var types = GetQualifiedTypes(functionParameters.Select(it => it.paramQualType), inClass.InFile); + var types = GetQualifiedTypes(parameters.Select(static it => it.paramQualType), inClass.InFile); position += AddImportsByName(types, sci.LineFromPosition(position)); - if (latest == null) sci.SetSel(position, sci.WordEndPosition(position, true)); + if (latest is null) sci.SetSel(position, sci.WordEndPosition(position, true)); else sci.SetSel(position, position); } + var generator = (ASGenerator) ASContext.Context.CodeGenerator; var newMember = NewMember(contextToken, isStatic, FlagType.Function, visibility); - newMember.Parameters = functionParameters.Select(parameter => new MemberModel(parameter.paramName, parameter.paramQualType, FlagType.ParameterVar, 0)).ToList(); + newMember.Parameters = parameters.Select(generator.ToParameterVar).ToList(); if (newMemberType != null) newMember.Type = newMemberType; - GenerateFunction(newMember, position, inClass, detach); + generator.GenerateFunction(sci, position, inClass, newMember, detach); } - static void GenerateFunction(MemberModel member, int position, ClassModel inClass, bool detach) + protected virtual void GenerateFunction(ScintillaControl sci, int position, ClassModel inClass, MemberModel member, bool detach) { string template; - string decl; if ((inClass.Flags & FlagType.Interface) > 0) { template = TemplateUtils.GetTemplate("IFunction"); - decl = TemplateUtils.ToDeclarationString(member, template); + template = TemplateUtils.ToDeclarationString(member, template); } else if ((member.Flags & FlagType.Constructor) > 0) { template = TemplateUtils.GetTemplate("Constructor"); - decl = TemplateUtils.ToDeclarationWithModifiersString(member, template); + template = ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(member, template); + string super = null; + if (inClass.ContainsMember(FlagType.Function | FlagType.Constructor, true)) + { + var value = new StringBuilder(); + foreach (var parameter in member.Parameters) + { + if (value.Length != 0) value.Append(", "); + value.Append(parameter.Name); + } + value.Insert(0, "super("); + value.Append(");"); + super = value.ToString(); + } + template = TemplateUtils.ReplaceTemplateVariable(template, "Super", super); + var line = sci.LineFromPosition(position); + if (GetDeclarationAtLine(line).Member != null) template += $"{NewLine}{NewLine}{NewLine}"; + else if (GetDeclarationAtLine(line + 1).Member != null) template += $"{NewLine}{NewLine}"; } else { - string body = null; - switch (ASContext.CommonSettings.GeneratedMemberDefaultBodyStyle) - { - case GeneratedMemberBodyStyle.ReturnDefaultValue: - var type = member.Type; - if (inClass.InFile.haXe) - { - var expr = inClass.InFile.Context.ResolveType(type, inClass.InFile); - if ((expr.Flags & FlagType.Abstract) != 0 && !string.IsNullOrEmpty(expr.ExtendsType)) - type = expr.ExtendsType; - } - var defaultValue = inClass.InFile.Context.GetDefaultValue(type); - if (!string.IsNullOrEmpty(defaultValue)) body = $"return {defaultValue};"; - break; - } + var body = GetFunctionBody(member, inClass); template = TemplateUtils.GetTemplate("Function"); - decl = TemplateUtils.ToDeclarationWithModifiersString(member, template); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Body", body); + template = ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(member, template); + template = TemplateUtils.ReplaceTemplateVariable(template, "Body", body); + } + GenerateFunction(position, template, detach); + } + + protected virtual string GetFunctionBody(MemberModel member, ClassModel inClass) + { + switch (ASContext.CommonSettings.GeneratedMemberDefaultBodyStyle) + { + case GeneratedMemberBodyStyle.ReturnDefaultValue: + var defaultValue = ASContext.Context.GetDefaultValue(member.Type); + if (!string.IsNullOrEmpty(defaultValue)) return $"return {defaultValue};"; + break; } - if (detach) decl = NewLine + TemplateUtils.ReplaceTemplateVariable(decl, "BlankLine", NewLine); - else decl = TemplateUtils.ReplaceTemplateVariable(decl, "BlankLine", null); - InsertCode(position, decl); + return null; } - static void GenerateClass(ScintillaControl sci, ClassModel inClass, ASExpr data) + protected void GenerateFunction(int position, string declaration, bool detach) { - var parameters = ParseFunctionParameters(sci, sci.WordEndPosition(data.PositionExpression, false)); - GenerateClass(inClass, data.Value, parameters); + if (detach) declaration = NewLine + TemplateUtils.ReplaceTemplateVariable(declaration, "BlankLine", NewLine); + else declaration = TemplateUtils.ReplaceTemplateVariable(declaration, "BlankLine", null); + InsertCode(position, declaration); } - static void GenerateClass(ScintillaControl sci, ClassModel inClass, string className) + static void GenerateClass(ScintillaControl sci, MemberModel inClass, ASExpr data) { - var parameters = ParseFunctionParameters(sci, sci.WordEndPosition(sci.CurrentPos, true)); - GenerateClass(inClass, className, parameters); + var position = sci.WordEndPosition(data.PositionExpression, false); + ((ASGenerator) ASContext.Context.CodeGenerator).GenerateClass(sci, position, inClass, data.Value); } - private static void GenerateClass(ClassModel inClass, string className, IList parameters) + static void GenerateClass(ScintillaControl sci, MemberModel inClass, string name) { - AddLookupPosition(); // remember last cursor position for Shift+F4 + var position = sci.WordEndPosition(sci.CurrentPos, true); + ((ASGenerator) ASContext.Context.CodeGenerator).GenerateClass(sci, position, inClass, name); + } + + protected void GenerateClass(ScintillaControl sci, int position, MemberModel inClass, string name) + => GenerateClass(sci, position, inClass, name, new Hashtable()); - List constructorArgs = new List(); - List constructorArgTypes = new List(); - MemberModel paramMember = new MemberModel(); - for (int i = 0; i < parameters.Count; i++) + protected virtual void GenerateClass(ScintillaControl sci, int position, MemberModel inClass, string name, Hashtable info) + { + AddLookupPosition(); // remember last cursor position for Shift+F4 + var parameters = ParseFunctionParameters(sci, position); + var constructorArgs = new List(parameters.Count); + var constructorArgTypes = new List(parameters.Count); + foreach (var p in parameters) { - FunctionParameter p = parameters[i]; constructorArgs.Add(new MemberModel(AvoidKeyword(p.paramName), p.paramType, FlagType.ParameterVar, 0)); constructorArgTypes.Add(CleanType(GetQualifiedType(p.paramQualType, inClass))); } - - paramMember.Parameters = constructorArgs; - - IProject project = PluginBase.CurrentProject; - if (String.IsNullOrEmpty(className)) className = "Class"; - string projFilesDir = Path.Combine(PathHelper.TemplateDir, "ProjectFiles"); - string projTemplateDir = Path.Combine(projFilesDir, project.GetType().Name); - string paramsString = TemplateUtils.ParametersString(paramMember, true); - Hashtable info = new Hashtable(); - info["className"] = className; - info["templatePath"] = Path.Combine(projTemplateDir, $"Class{ASContext.Context.Settings.DefaultExtension}.fdt"); + var paramMember = new MemberModel {Parameters = constructorArgs}; + var paramsString = TemplateUtils.ParametersString(paramMember, true); + info["className"] = string.IsNullOrEmpty(name) ? "Class" : name; + info["templatePath"] = Path.Combine(PathHelper.TemplateDir, "ProjectFiles", PluginBase.CurrentProject.GetType().Name, $"Class{ASContext.Context.Settings.DefaultExtension}.fdt"); info["inDirectory"] = Path.GetDirectoryName(inClass.InFile.FileName); info["constructorArgs"] = paramsString.Length > 0 ? paramsString : null; info["constructorArgTypes"] = constructorArgTypes; - DataEvent de = new DataEvent(EventType.Command, "ProjectManager.CreateNewFile", info); + var de = new DataEvent(EventType.Command, "ProjectManager.CreateNewFile", info); EventManager.DispatchEvent(null, de); } - public static void GenerateExtractVariable(ScintillaControl sci, string newName) - { - string expression = sci.SelText.Trim(new char[] { '=', ' ', '\t', '\n', '\r', ';', '.' }); - expression = expression.TrimEnd(new char[] { '(', '[', '{', '<' }); - expression = expression.TrimStart(new char[] { ')', ']', '}', '>' }); - - var cFile = ASContext.Context.CurrentModel; - ASFileParser parser = new ASFileParser(); - parser.ParseSrc(cFile, sci.Text); - - MemberModel current = cFile.Context.CurrentMember; - - string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; - - int funcBodyStart = GetBodyStart(current.LineFrom, current.LineTo, sci); - sci.SetSel(funcBodyStart, sci.LineEndPosition(current.LineTo)); - string currentMethodBody = sci.SelText; - var insertPosition = funcBodyStart + currentMethodBody.IndexOfOrdinal(expression); - var line = sci.LineFromPosition(insertPosition); - insertPosition = sci.LineIndentPosition(line); - - int lastPos = -1; - sci.Colourise(0, -1); - while (true) - { - lastPos = currentMethodBody.IndexOfOrdinal(expression, lastPos + 1); - if (lastPos > -1) - { - char prevOrNextChar; - if (lastPos > 0) - { - prevOrNextChar = currentMethodBody[lastPos - 1]; - if (characterClass.IndexOf(prevOrNextChar) > -1) - { - continue; - } - } - if (lastPos + expression.Length < currentMethodBody.Length) - { - prevOrNextChar = currentMethodBody[lastPos + expression.Length]; - if (characterClass.IndexOf(prevOrNextChar) > -1) - { - continue; - } - } - - var pos = funcBodyStart + lastPos; - int style = sci.BaseStyleAt(pos); - if (ASComplete.IsCommentStyle(style)) continue; - sci.SetSel(pos, pos + expression.Length); - sci.ReplaceSel(newName); - currentMethodBody = currentMethodBody.Substring(0, lastPos) + newName + currentMethodBody.Substring(lastPos + expression.Length); - lastPos += newName.Length; - } - else - { - break; - } - } - - sci.CurrentPos = insertPosition; - sci.SetSel(sci.CurrentPos, sci.CurrentPos); - MemberModel m = new MemberModel(newName, "", FlagType.LocalVar, 0); - m.Value = expression; + static void GenerateInterface(ScintillaControl sci, MemberModel inClass, string name) + => ((ASGenerator)ASContext.Context.CodeGenerator).GenerateInterface(sci, inClass, name, new Hashtable()); - string snippet = TemplateUtils.GetTemplate("Variable"); - snippet = TemplateUtils.ReplaceTemplateVariable(snippet, "Modifiers", null); - snippet = TemplateUtils.ToDeclarationString(m, snippet); - snippet += NewLine + "$(Boundary)"; - SnippetHelper.InsertSnippetText(sci, sci.CurrentPos, snippet); + protected virtual void GenerateInterface(ScintillaControl sci, MemberModel inClass, string name, Hashtable info) + { + AddLookupPosition(); // remember last cursor position for Shift+F4 + info["interfaceName"] = string.IsNullOrEmpty(name) ? "IInterface" : name; + info["templatePath"] = Path.Combine(PathHelper.TemplateDir, "ProjectFiles", PluginBase.CurrentProject.GetType().Name, $"Interface{ASContext.Context.Settings.DefaultExtension}.fdt"); + info["inDirectory"] = Path.GetDirectoryName(inClass.InFile.FileName); + var de = new DataEvent(EventType.Command, "ProjectManager.CreateNewFile", info); + EventManager.DispatchEvent(null, de); } public static void GenerateExtractMethod(ScintillaControl sci, string newName) { - string selection = sci.SelText; - if (string.IsNullOrEmpty(selection)) - { - return; - } + var selection = sci.SelText; + if (string.IsNullOrEmpty(selection)) return; var trimmedLength = selection.TrimStart().Length; if (trimmedLength == 0) return; @@ -3284,43 +3019,32 @@ public static void GenerateExtractMethod(ScintillaControl sci, string newName) } InsertCode(sci.CurrentPos, template, sci); - var cFile = ASContext.Context.CurrentModel; - ASFileParser parser = new ASFileParser(); - parser.ParseSrc(cFile, sci.Text); - - FoundDeclaration found = GetDeclarationAtLine(lineStart); - if (found.Member == null) return; + var ctx = ASContext.Context; + ctx.GetCodeModel(ctx.CurrentModel, sci.Text); + var found = ((ASGenerator) ctx.CodeGenerator).GetDeclarationAtLine(lineStart); + if (found.Member is null) return; lookupPosition = sci.CurrentPos; AddLookupPosition(); - MemberModel latest = TemplateUtils.GetTemplateBlockMember(sci, TemplateUtils.GetBoundary("PrivateMethods")); + var latest = TemplateUtils.GetTemplateBlockMember(sci, TemplateUtils.GetBoundary("PrivateMethods")) + ?? GetLatestMemberForFunction(found.InClass, GetDefaultVisibility(found.InClass), found.Member) + ?? found.Member; - if (latest == null) - latest = GetLatestMemberForFunction(found.InClass, GetDefaultVisibility(found.InClass), found.Member); - - if (latest == null) - latest = found.Member; - - int position = sci.PositionFromLine(latest.LineTo + 1) - ((sci.EOLMode == 0) ? 2 : 1); + var position = sci.PositionFromLine(latest.LineTo + 1) - ((sci.EOLMode == 0) ? 2 : 1); sci.SetSel(position, position); - FlagType flags = FlagType.Function; - if ((found.Member.Flags & FlagType.Static) > 0) - { - flags |= FlagType.Static; - } - - MemberModel m = new MemberModel(newName, ASContext.Context.Features.voidKey, flags, GetDefaultVisibility(found.InClass)); - + var flags = FlagType.Function; + if ((found.Member.Flags & FlagType.Static) > 0) flags |= FlagType.Static; + var member = new MemberModel(newName, ctx.Features.voidKey, flags, GetDefaultVisibility(found.InClass)); template = NewLine + TemplateUtils.GetTemplate("Function"); - template = TemplateUtils.ToDeclarationWithModifiersString(m, template); + template = ((ASGenerator) ctx.CodeGenerator).ToDeclarationWithModifiersString(member, template); template = TemplateUtils.ReplaceTemplateVariable(template, "Body", selText); template = TemplateUtils.ReplaceTemplateVariable(template, "BlankLine", NewLine); InsertCode(position, template, sci); } - private static int FindNewVarPosition(ScintillaControl sci, ClassModel inClass, MemberModel latest) + static int FindNewVarPosition(ScintillaControl sci, MemberModel inClass, MemberModel latest) { firstVar = false; // found a var? @@ -3330,7 +3054,7 @@ private static int FindNewVarPosition(ScintillaControl sci, ClassModel inClass, // add as first member int line = 0; int maxLine = sci.LineCount; - if (inClass != null) + if (inClass is not null) { line = inClass.LineFrom; maxLine = inClass.LineTo; @@ -3339,8 +3063,8 @@ private static int FindNewVarPosition(ScintillaControl sci, ClassModel inClass, else maxLine = ASContext.Context.CurrentModel.PrivateSectionIndex; while (line < maxLine) { - string text = sci.GetLine(line++); - if (text.IndexOf('{') >= 0) + var text = sci.GetLine(line++); + if (text.Contains('{')) { firstVar = true; return sci.PositionFromLine(line) - ((sci.EOLMode == 0) ? 2 : 1); @@ -3349,14 +3073,14 @@ private static int FindNewVarPosition(ScintillaControl sci, ClassModel inClass, return -1; } - private static bool RemoveLocalDeclaration(ScintillaControl sci, MemberModel contextMember) + static bool RemoveLocalDeclaration(ScintillaControl sci, MemberModel contextMember) { int removed = 0; - if (contextResolved != null) + if (contextResolved is not null) { - contextResolved.Context.LocalVars.Items.Sort(new ByDeclarationPositionMemberComparer()); + contextResolved.Context.LocalVars.Items.Sort(ByDeclarationPositionMemberComparer.Instance); contextResolved.Context.LocalVars.Items.Reverse(); - foreach (MemberModel member in contextResolved.Context.LocalVars) + foreach (var member in contextResolved.Context.LocalVars) { if (member.Name == contextMember.Name) { @@ -3365,81 +3089,69 @@ private static bool RemoveLocalDeclaration(ScintillaControl sci, MemberModel con } } } - if (removed == 0) return RemoveOneLocalDeclaration(sci, contextMember); - else return true; + return removed != 0 || RemoveOneLocalDeclaration(sci, contextMember); } - private static bool RemoveOneLocalDeclaration(ScintillaControl sci, MemberModel contextMember) + static bool RemoveOneLocalDeclaration(ScintillaControl sci, MemberModel contextMember) { string type = ""; - if (contextMember.Type != null && (contextMember.Flags & FlagType.Inferred) == 0) - { - type = FormatType(contextMember.Type); - if (type.IndexOf('*') > 0) - type = type.Replace("/*", @"/\*\s*").Replace("*/", @"\s*\*/"); - type = @":\s*" + type; - } - var name = contextMember.Name; - Regex reDecl = new Regex(String.Format(@"[\s\(]((var|const)\s+{0}\s*{1})\s*", name, type)); - for (int i = contextMember.LineFrom; i <= contextMember.LineTo + 10; i++) + if (contextMember.Type is not null && (contextMember.Flags & FlagType.Inferred) == 0) { - string text = sci.GetLine(i); - Match m = reDecl.Match(text); - if (m.Success) + // for example: var f:Function/*(v1:Type):void*/ + if ((contextMember.Flags & FlagType.Function) != 0) type = ":\\s*Function\\/\\*.*\\*\\/"; + else { - int index = sci.MBSafeTextLength(text.Substring(0, m.Groups[1].Index)); - int position = sci.PositionFromLine(i) + index; - int len = sci.MBSafeTextLength(m.Groups[1].Value); - sci.SetSel(position, position + len); - if (ASContext.CommonSettings.GenerateScope) name = "this." + name; - if (contextMember.Type == null || (contextMember.Flags & FlagType.Inferred) != 0) name += " "; - sci.ReplaceSel(name); - UpdateLookupPosition(position, name.Length - len); - return true; + type = MemberModel.FormatType(contextMember.Type); + if (type.IndexOf('*') > 0) + type = type.Replace("/*", @"/\*\s*").Replace("*/", @"\s*\*/"); + type = @":\s*" + type; } } + var name = contextMember.Name; + var reDecl = new Regex($@"[\s\(]((var|const)\s+{name}\s*{type})\s*"); + for (var i = contextMember.LineFrom; i <= contextMember.LineTo + 10; i++) + { + var text = sci.GetLine(i); + var m = reDecl.Match(text); + if (!m.Success) continue; + var index = sci.MBSafeTextLength(text.Substring(0, m.Groups[1].Index)); + var position = sci.PositionFromLine(i) + index; + var len = sci.MBSafeTextLength(m.Groups[1].Value); + sci.SetSel(position, position + len); + if (ASContext.CommonSettings.GenerateScope) name = "this." + name; + if (contextMember.Type is null || (contextMember.Flags & FlagType.Inferred) != 0) name += " "; + sci.ReplaceSel(name); + UpdateLookupPosition(position, name.Length - len); + return true; + } return false; } internal static StatementReturnType GetStatementReturnType(ScintillaControl sci, ClassModel inClass, string line, int startPos) { - Regex target = new Regex(@"[;\s\n\r]*", RegexOptions.RightToLeft); - Match m = target.Match(line); + var target = new Regex(@"[;\s\n\r]*", RegexOptions.RightToLeft); + var m = target.Match(line); if (!m.Success) return null; line = line.Substring(0, m.Index); if (line.Length == 0) return null; var pos = startPos + m.Index; var expr = ASComplete.GetExpressionType(sci, pos, false, true); - if (expr.Type != null || expr.Member != null) pos = expr.Context.Position; + if (expr.Type is not null || expr.Member is not null) pos = expr.Context.Position; var ctx = inClass.InFile.Context; var features = ctx.Features; - ASResult resolve = expr; - if (resolve.Type != null && !resolve.IsPackage) + var resolve = expr; + if (resolve.Type is not null && !resolve.IsPackage) { if (resolve.Type.Name == "Function") { - if (IsHaxe) - { - var voidKey = features.voidKey; - var parameters = resolve.Member.Parameters?.Select(it => it.Type).ToList() ?? new List {voidKey}; - parameters.Add(resolve.Member.Type ?? voidKey); - var qualifiedName = string.Empty; - for (var i = 0; i < parameters.Count; i++) - { - if (i > 0) qualifiedName += "->"; - var t = parameters[i]; - if (t.Contains("->") && !t.StartsWith('(')) t = $"({t})"; - qualifiedName += t; - } - resolve = new ASResult {Type = new ClassModel {Name = qualifiedName, InFile = FileModel.Ignore}}; - } - else resolve.Member = null; + var type = ctx.CodeComplete.ToFunctionDeclarationString(expr.Member); + resolve = new ASResult {Type = new ClassModel {Name = type, InFile = FileModel.Ignore}, Context = expr.Context}; } else if (!string.IsNullOrEmpty(resolve.Path) && Regex.IsMatch(resolve.Path, @"(\.\[.{0,}?\])$", RegexOptions.RightToLeft)) resolve.Member = null; } var word = sci.GetWordFromPosition(pos); - if (string.IsNullOrEmpty(word) && resolve.Type != null) + if (string.IsNullOrEmpty(word) && resolve.Type is not null) { var tokens = Regex.Split(resolve.Context.Value, Regex.Escape(features.dot)); word = tokens.LastOrDefault(it => it.Length > 0 && !(it.Length >= 2 && it[0] == '#' && it[it.Length - 1] == '~') && char.IsLetter(it[0])); @@ -3447,161 +3159,142 @@ internal static StatementReturnType GetStatementReturnType(ScintillaControl sci, return new StatementReturnType(resolve, pos, word); } - private static string GuessVarName(string name, string type) + protected internal static string GuessVarName(string name, string type) { + if (name == "_") name = null; if (string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(type)) { - Match m = Regex.Match(type, "^([a-z0-9_$]+)", RegexOptions.IgnoreCase); - if (m.Success) - name = m.Groups[1].Value; - else - name = type; + var m = Regex.Match(type, "^([a-z0-9_$]+)", RegexOptions.IgnoreCase); + name = m.Success + ? m.Groups[1].Value + : type; } - if (string.IsNullOrEmpty(name)) - return name; + if (string.IsNullOrEmpty(name)) return name; // if constant then convert to camelCase - if (name.ToUpper() == name) - name = Camelize(name); + if (name.ToUpper() == name) name = Camelize(name); // if getter, then remove 'get' prefix - name = name.TrimStart(new char[] { '_' }); - if (name.Length > 3 && name.StartsWithOrdinal("get") && (name[3].ToString() == char.ToUpper(name[3]).ToString())) + name = name.TrimStart('_'); + if (name.Length > 3 && name.StartsWithOrdinal("get")) { - name = char.ToLower(name[3]) + name.Substring(4); + var c = name[3]; + if (!char.IsDigit(c) && c.ToString() == char.ToUpper(c).ToString()) + { + name = char.ToLower(c) + name.Substring(4); + } } - if (name.Length > 1) - name = Char.ToLower(name[0]) + name.Substring(1); - else - name = Char.ToLower(name[0]) + ""; - - if (name == "this" || type == name) + if (name.Length > 1) name = char.ToLower(name[0]) + name.Substring(1); + else name = char.ToLower(name[0]) + ""; + var features = ASContext.Context.Features; + if (name == features.ThisKey || name == features.BaseKey || type == name) { if (!string.IsNullOrEmpty(type)) - name = Char.ToLower(type[0]) + type.Substring(1); - else - name = "p_this"; + { + // for example: int -> intValue + if (char.IsLower(type[0])) return name + "Value"; + // for example: Number -> number + return char.ToLower(type[0]) + type.Substring(1); + } + if (name == features.BaseKey) return "p_super"; + return "p_this"; } return name; } - private static void GenerateImplementation(ClassModel iType, ClassModel inClass, ScintillaControl sci, bool detached) + static void GenerateImplementation(ClassModel iType, ClassModel inClass, ScintillaControl sci, bool detached) { var typesUsed = new HashSet(); - - StringBuilder sb = new StringBuilder(); - - string header = TemplateUtils.ReplaceTemplateVariable(TemplateUtils.GetTemplate("ImplementHeader"), "Class", iType.Type); - + var header = TemplateUtils.ReplaceTemplateVariable(TemplateUtils.GetTemplate("ImplementHeader"), "Class", iType.Type); header = TemplateUtils.ReplaceTemplateVariable(header, "BlankLine", detached ? BlankLine : null); - + var sb = new StringBuilder(); sb.Append(header); sb.Append(NewLine); - bool entry = true; - ASResult result = new ASResult(); - IASContext context = ASContext.Context; - ContextFeatures features = context.Features; - bool canGenerate = false; - bool isHaxe = IsHaxe; - FlagType flags = (FlagType.Function | FlagType.Getter | FlagType.Setter); + var entry = true; + var result = new ASResult(); + var ctx = ASContext.Context; + var features = ctx.Features; + var codeGenerator = (ASGenerator) ctx.CodeGenerator; + var canGenerate = false; + var isHaxe = IsHaxe; + var flags = FlagType.Function | FlagType.Getter | FlagType.Setter; if (isHaxe) flags |= FlagType.Variable; - iType.ResolveExtends(); // resolve inheritance chain + iType.ResolveExtends(); // expr inheritance chain while (!iType.IsVoid() && iType.QualifiedName != "Object") { - foreach (MemberModel method in iType.Members) + foreach (var method in iType.Members) { - if ((method.Flags & flags) == 0 - || method.Name == iType.Name) + if ((method.Flags & flags) == 0 || method.Name == iType.Name) continue; // check if method exists ASComplete.FindMember(method.Name, inClass, result, method.Flags, 0); if (!result.IsNull()) continue; - string decl; + string template; if ((method.Flags & FlagType.Getter) > 0) { - if (isHaxe) + // for example: function get foo():Function/*(v:*):int*/ + if ((method.Flags & FlagType.Function) != 0 && method.Parameters is not null) + method.Type = ctx.CodeComplete.ToFunctionDeclarationString(method); + template = codeGenerator.GetGetterImplementationTemplate(method); + } + else if ((method.Flags & FlagType.Setter) > 0) + { + // for example: function get set(v:Function/*(v:*):int*/):void + if (!method.Parameters.IsNullOrEmpty()) { - decl = TemplateUtils.ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Property")); - - string templateName = null; - string metadata = null; - if (method.Parameters[0].Name == "get") - { - if (method.Parameters[1].Name == "set") - { - templateName = "GetterSetter"; - metadata = "@:isVar"; - } - else - templateName = "Getter"; - } - else if (method.Parameters[1].Name == "set") - { - templateName = "Setter"; - } - - decl = TemplateUtils.ReplaceTemplateVariable(decl, "MetaData", metadata); - - if (templateName != null) - { - var accessor = NewLine + TemplateUtils.ToDeclarationString(method, TemplateUtils.GetTemplate(templateName)); - accessor = TemplateUtils.ReplaceTemplateVariable(accessor, "Modifiers", null); - accessor = TemplateUtils.ReplaceTemplateVariable(accessor, "Member", method.Name); - decl += accessor; - } + var parameter = method.Parameters[0]; + if ((parameter.Flags & FlagType.Function) != 0 && parameter.Parameters is not null) + parameter.Type = ctx.CodeComplete.ToFunctionDeclarationString(parameter); } - else - decl = TemplateUtils.ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Getter")); + template = ((ASGenerator) ctx.CodeGenerator).ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Setter")); } - else if ((method.Flags & FlagType.Setter) > 0) - decl = TemplateUtils.ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Setter")); else if ((method.Flags & FlagType.Function) > 0) - decl = TemplateUtils.ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Function")); - else - decl = NewLine + TemplateUtils.ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Variable")); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Member", "_" + method.Name); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Void", features.voidKey); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Body", null); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "BlankLine", NewLine); - - if (!entry) { - decl = TemplateUtils.ReplaceTemplateVariable(decl, "EntryPoint", null); + // for example: function get set(v:Function/*(v:*):int*/):void + if (method.Parameters is not null) + { + foreach (var parameter in method.Parameters) + { + if ((parameter.Flags & FlagType.Function) != 0 && parameter.Parameters is not null) + parameter.Type = ctx.CodeComplete.ToFunctionDeclarationString(parameter); + } + } + template = ((ASGenerator) ctx.CodeGenerator).ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Function")); } - - decl += NewLine; - + else template = NewLine + ((ASGenerator) ctx.CodeGenerator).ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Variable")); + + template = TemplateUtils.ReplaceTemplateVariable(template, "Member", "_" + method.Name); + template = TemplateUtils.ReplaceTemplateVariable(template, "Void", features.voidKey); + template = TemplateUtils.ReplaceTemplateVariable(template, "Body", codeGenerator.GetFunctionBody(method, inClass)); + template = TemplateUtils.ReplaceTemplateVariable(template, "BlankLine", NewLine); + if (!entry) template = TemplateUtils.ReplaceTemplateVariable(template, "EntryPoint", null); + template += NewLine; entry = false; - - sb.Append(decl); + sb.Append(template); canGenerate = true; - - typesUsed.Add(method.Type); - - if (method.Parameters != null && method.Parameters.Count > 0) - foreach (MemberModel param in method.Parameters) + if (method.Type != features.voidKey) typesUsed.Add(method.Type); + if (!method.Parameters.IsNullOrEmpty()) + foreach (var param in method.Parameters) typesUsed.Add(param.Type); } - if (ASContext.Context.Settings.GenerateImports) typesUsed = (HashSet) GetQualifiedTypes(typesUsed, iType.InFile); + + if (ctx.Settings.GenerateImports) typesUsed = (HashSet) GetQualifiedTypes(typesUsed, iType.InFile); // interface inheritance iType = iType.Extends; } - if (!canGenerate) - return; - + if (!canGenerate) return; sci.BeginUndoAction(); try { - int position = sci.CurrentPos; - if (ASContext.Context.Settings.GenerateImports && typesUsed.Count > 0) + var position = sci.CurrentPos; + if (ctx.Settings.GenerateImports && typesUsed.Count > 0) { - int offset = AddImportsByName(typesUsed, sci.LineFromPosition(position)); - position += offset; + position += AddImportsByName(typesUsed, sci.LineFromPosition(position)); sci.SetSel(position, position); } InsertCode(position, sb.ToString(), sci); @@ -3609,12 +3302,14 @@ private static void GenerateImplementation(ClassModel iType, ClassModel inClass, finally { sci.EndUndoAction(); } } - private static void AddTypeOnce(List typesUsed, string qualifiedName) + protected virtual string GetGetterImplementationTemplate(MemberModel method) => ToDeclarationWithModifiersString(method, TemplateUtils.GetTemplate("Getter")); + + static void AddTypeOnce(ICollection typesUsed, string qualifiedName) { if (!typesUsed.Contains(qualifiedName)) typesUsed.Add(qualifiedName); } - static IEnumerable GetQualifiedTypes(IEnumerable types, FileModel inFile) + protected static IEnumerable GetQualifiedTypes(IEnumerable types, FileModel inFile) { var result = new HashSet(); types = ASContext.Context.DecomposeTypes(types); @@ -3630,64 +3325,58 @@ static IEnumerable GetQualifiedTypes(IEnumerable types, FileMode return result; } - private static string GetQualifiedType(string type, ClassModel aType) + static string GetQualifiedType(string type, MemberModel aType) { var dynamicKey = ASContext.Context.Features.dynamicKey ?? "*"; if (string.IsNullOrEmpty(type)) return dynamicKey; if (ASContext.Context.DecomposeTypes(new [] {type}).Count() > 1) return type; if (type.IndexOf('<') > 0) // Vector. { - Match mGeneric = Regex.Match(type, "<([^>]+)>"); - if (mGeneric.Success) - { - return GetQualifiedType(mGeneric.Groups[1].Value, aType); - } + var mGeneric = Regex.Match(type, "<([^>]+)>"); + if (mGeneric.Success) return GetQualifiedType(mGeneric.Groups[1].Value, aType); } - if (type.IndexOf('.') > 0) return type; - - ClassModel aClass = ASContext.Context.ResolveType(type, aType.InFile); - if (!aClass.IsVoid()) - { - return aClass.QualifiedName; - } - return dynamicKey; + var aClass = ASContext.Context.ResolveType(type, aType.InFile); + return !aClass.IsVoid() + ? aClass.QualifiedName + : dynamicKey; } - private static MemberModel NewMember(string contextToken, MemberModel calledFrom, FlagType kind, Visibility visi) + static MemberModel NewMember(string name, MemberModel calledFrom, FlagType kind, Visibility access) { - string type = (kind == FlagType.Function && !ASContext.Context.Features.hasInference) - ? ASContext.Context.Features.voidKey : null; - if (calledFrom != null && (calledFrom.Flags & FlagType.Static) > 0) + var type = kind == FlagType.Function && !ASContext.Context.Features.hasInference + ? ASContext.Context.Features.voidKey + : null; + if (calledFrom is not null && (calledFrom.Flags & FlagType.Static) > 0) kind |= FlagType.Static; - return new MemberModel(contextToken, type, kind, visi); + return new MemberModel(name, type, kind, access); } /// /// Get Visibility.Private or Visibility.Protected, depending on user setting forcing the use of protected. /// - private static Visibility GetDefaultVisibility(ClassModel model) + static Visibility GetDefaultVisibility(MemberModel model) { - if (ASContext.Context.Features.protectedKey != null - && ASContext.CommonSettings.GenerateProtectedDeclarations - && (model.Flags & FlagType.Final) == 0) + if (ASContext.Context.Features.protectedKey is not null + && ASContext.CommonSettings.GenerateProtectedDeclarations + && (model.Flags & FlagType.Final) == 0) return Visibility.Protected; - return Visibility.Private; + return Visibility.Private; } - private static void GenerateVariable(MemberModel member, int position, bool detach) + static void GenerateVariable(MemberModel member, int position, bool detach) { string result; if ((member.Flags & FlagType.Constant) > 0) { - string template = TemplateUtils.GetTemplate("Constant"); - result = TemplateUtils.ToDeclarationWithModifiersString(member, template); + var template = TemplateUtils.GetTemplate("Constant"); + result = ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(member, template); result = TemplateUtils.ReplaceTemplateVariable(result, "Value", member.Value); } else { - string template = TemplateUtils.GetTemplate("Variable"); - result = TemplateUtils.ToDeclarationWithModifiersString(member, template); + var template = TemplateUtils.GetTemplate("Variable"); + result = ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(member, template); } if (firstVar) @@ -3699,85 +3388,49 @@ private static void GenerateVariable(MemberModel member, int position, bool deta InsertCode(position, result); } - public static bool MakePrivate(ScintillaControl Sci, MemberModel member, ClassModel inClass) + public static bool MakePrivate(ScintillaControl sci, MemberModel member, ClassModel inClass) { - ContextFeatures features = ASContext.Context.Features; - string visibility = GetPrivateKeyword(inClass); - if (features.publicKey == null || visibility == null) return false; - Regex rePublic = new Regex(String.Format(@"\s*({0})\s+", features.publicKey)); - - for (int i = member.LineFrom; i <= member.LineTo; i++) + var features = ASContext.Context.Features; + var visibility = GetPrivateKeyword(inClass); + if (features.publicKey is null || visibility is null) return false; + var rePublic = new Regex($@"\s*({features.publicKey})\s+"); + for (var i = member.LineFrom; i <= member.LineTo; i++) { - var line = Sci.GetLine(i); + var line = sci.GetLine(i); var m = rePublic.Match(line); if (m.Success) { - var index = Sci.MBSafeTextLength(line.Substring(0, m.Groups[1].Index)); - var position = Sci.PositionFromLine(i) + index; - Sci.SetSel(position, position + features.publicKey.Length); - Sci.ReplaceSel(visibility); + var index = sci.MBSafeTextLength(line.Substring(0, m.Groups[1].Index)); + var position = sci.PositionFromLine(i) + index; + sci.SetSel(position, position + features.publicKey.Length); + sci.ReplaceSel(visibility); UpdateLookupPosition(position, features.publicKey.Length - visibility.Length); return true; } } return false; - } - - public static bool MakeHaxeProperty(ScintillaControl Sci, MemberModel member, string args) - { - ContextFeatures features = ASContext.Context.Features; - string kind = features.varKey; - - if ((member.Flags & FlagType.Getter) > 0) - kind = features.getKey; - else if ((member.Flags & FlagType.Setter) > 0) - kind = features.setKey; - else if (member.Flags == FlagType.Function) - kind = features.functionKey; - - Regex reMember = new Regex(String.Format(@"{0}\s+({1})[\s:]", kind, member.Name)); - - for (int i = member.LineFrom; i <= member.LineTo; i++) - { - var line = Sci.GetLine(i); - var m = reMember.Match(line); - if (m.Success) - { - var index = Sci.MBSafeTextLength(line.Substring(0, m.Groups[1].Index)); - var position = Sci.PositionFromLine(i) + index; - Sci.SetSel(position, position + member.Name.Length); - Sci.ReplaceSel(member.Name + args); - UpdateLookupPosition(position, 1); - return true; - } - } - return false; - } - - public static bool RenameMember(ScintillaControl Sci, MemberModel member, string newName) - { - ContextFeatures features = ASContext.Context.Features; - string kind = features.varKey; - - if ((member.Flags & FlagType.Getter) > 0) - kind = features.getKey; - else if ((member.Flags & FlagType.Setter) > 0) - kind = features.setKey; - else if (member.Flags == FlagType.Function) - kind = features.functionKey; - - Regex reMember = new Regex(String.Format(@"{0}\s+({1})[\s:]", kind, member.Name)); - - for (int i = member.LineFrom; i <= member.LineTo; i++) - { - var line = Sci.GetLine(i); + } + + public static bool RenameMember(ScintillaControl sci, MemberModel member, string newName) + { + var features = ASContext.Context.Features; + var kind = features.varKey; + + if ((member.Flags & FlagType.Getter) > 0) kind = features.getKey; + else if ((member.Flags & FlagType.Setter) > 0) kind = features.setKey; + else if (member.Flags == FlagType.Function) kind = features.functionKey; + + var reMember = new Regex($@"{kind}\s+({member.Name})[\s:]"); + for (var i = member.LineFrom; i <= member.LineTo; i++) + { + var line = sci.GetLine(i); var m = reMember.Match(line); if (m.Success) { - var index = Sci.MBSafeTextLength(line.Substring(0, m.Groups[1].Index)); - var position = Sci.PositionFromLine(i) + index; - Sci.SetSel(position, position + member.Name.Length); - Sci.ReplaceSel(newName); + var index = sci.MBSafeTextLength(line.Substring(0, m.Groups[1].Index)); + var position = sci.PositionFromLine(i) + index; + sci.SetSel(position, position + member.Name.Length); + sci.ReplaceSel(newName); UpdateLookupPosition(position, 1); return true; } @@ -3787,71 +3440,65 @@ public static bool RenameMember(ScintillaControl Sci, MemberModel member, string /// /// Return an obvious property name matching a private var, or null - /// - private static string GetPropertyNameFor(MemberModel member) - { - string name = member.Name; - if (name.Length == 0 || (member.Access & Visibility.Public) > 0 || IsHaxe) return null; - Match parts = Regex.Match(name, "([^_$]*)[_$]+(.*)"); - if (parts.Success) - { - string pre = parts.Groups[1].Value; - string post = parts.Groups[2].Value; - return pre.Length > post.Length ? pre : post; - } - return null; + /// + static string GetPropertyNameFor(MemberModel member) + { + if (IsHaxe) return null; + var name = member.Name; + if (name.Length == 0 || (member.Access & Visibility.Public) != 0) return null; + var parts = Regex.Match(name, "([^_$]*)[_$]+(.*)"); + if (!parts.Success) return null; + var pre = parts.Groups[1].Value; + var post = parts.Groups[2].Value; + return pre.Length > post.Length ? pre : post; } /// /// Return a smart new property name /// - private static string GetNewPropertyNameFor(MemberModel member) + static string GetNewPropertyNameFor(MemberModel member) { - if (member.Name.Length == 0) - return "prop"; + if (member.Name.Length == 0) return "prop"; if (Regex.IsMatch(member.Name, "^[A-Z].*[a-z]")) - return Char.ToLower(member.Name[0]) + member.Name.Substring(1); - else - return "_" + member.Name; + return char.ToLower(member.Name[0]) + member.Name.Substring(1); + return "_" + member.Name; } - private static void GenerateDelegateMethod(string name, MemberModel afterMethod, int position, ClassModel inClass) + static void GenerateDelegateMethod(string name, MemberModel afterMethod, int position, ClassModel inClass) { - ContextFeatures features = ASContext.Context.Features; - - string acc = GetPrivateAccessor(afterMethod, inClass); - string template = TemplateUtils.GetTemplate("Delegate"); + var features = ASContext.Context.Features; string args = null; - string type = features.voidKey; - - if (features.hasDelegates && contextMember != null) // delegate functions types + var type = features.voidKey; + if (features.hasDelegates && contextMember is not null) // delegate functions types { args = contextMember.ParametersString(); type = contextMember.Type; } - string decl = BlankLine + TemplateUtils.ReplaceTemplateVariable(template, "Modifiers", acc); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Name", name); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Arguments", args); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Type", type); - InsertCode(position, decl); + var template = TemplateUtils.GetTemplate("Delegate"); + template = BlankLine + TemplateUtils.ReplaceTemplateVariable(template, "Modifiers", GetPrivateAccessor(afterMethod, inClass)); + template = TemplateUtils.ReplaceTemplateVariable(template, "Name", name); + template = TemplateUtils.ReplaceTemplateVariable(template, "Arguments", args); + template = TemplateUtils.ReplaceTemplateVariable(template, "Type", type); + InsertCode(position, template); } - private static void GenerateEventHandler(string name, string type, MemberModel afterMethod, int position, ClassModel inClass) + static void GenerateEventHandler(string name, string type, MemberModel afterMethod, int position, ClassModel inClass) { - ScintillaControl sci = ASContext.CurSciControl; + var ctx = ASContext.Context; + var sci = PluginBase.MainForm.CurrentDocument.SciControl; sci.BeginUndoAction(); try { - int delta = 0; - ClassModel eventClass = ASContext.Context.ResolveType(type, ASContext.Context.CurrentModel); + var delta = 0; + var eventClass = ctx.ResolveType(type, ctx.CurrentModel); if (eventClass.IsVoid()) - { - if (TryImportType("flash.events." + type, ref delta, sci.LineFromPosition(position))) - { - position += delta; - sci.SetSel(position, position); - } + { + if (TryImportType("flash.events." + type, ref delta, sci.LineFromPosition(position))) + { + position += delta; + sci.SetSel(position, position); + } else type = null; } lookupPosition += delta; @@ -3863,45 +3510,55 @@ private static void GenerateEventHandler(string name, string type, MemberModel a }; if ((afterMethod.Flags & FlagType.Static) > 0) newMember.Flags = FlagType.Static; var template = TemplateUtils.GetTemplate("EventHandler"); - var decl = NewLine + TemplateUtils.ToDeclarationWithModifiersString(newMember, template); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Void", ASContext.Context.Features.voidKey); - - string eventName = contextMatch.Groups["event"].Value; - string autoRemove = AddRemoveEvent(eventName); - if (autoRemove != null) - { - if (autoRemove.Length == 0 && ASContext.CommonSettings.GenerateScope) autoRemove = "this"; - if (autoRemove.Length > 0) autoRemove += "."; - string remove = string.Format("{0}removeEventListener({1}, {2});\n\t$(EntryPoint)", autoRemove, eventName, name); - decl = decl.Replace("$(EntryPoint)", remove); - } - InsertCode(position, decl, sci); + var declaration = NewLine + ((ASGenerator) ctx.CodeGenerator).ToDeclarationWithModifiersString(newMember, template); + declaration = TemplateUtils.ReplaceTemplateVariable(declaration, "Void", ctx.Features.voidKey); + var eventName = contextMatch.Groups["event"].Value; + var autoRemove = AddRemoveEvent(eventName); + ((ASGenerator) ctx.CodeGenerator).GenerateEventHandler(sci, position, declaration, autoRemove, eventName, name); } finally { sci.EndUndoAction(); } - } - - private static bool TryImportType(string type, ref int delta, int atLine) - { - ClassModel eventClass = ASContext.Context.ResolveType(type, ASContext.Context.CurrentModel); - if (eventClass.IsVoid()) - return false; - - List typesUsed = new List(); - typesUsed.Add(type); - delta += AddImportsByName(typesUsed, atLine); - return true; } - private static string AddRemoveEvent(string eventName) + protected virtual void GenerateEventHandler(ScintillaControl sci, int position, string template, string currentTarget, string eventName, string handlerName) + { + var ctx = ASContext.Context; + if (currentTarget is not null) + { + var delta = 0; + if (TryImportType("flash.events.IEventDispatcher", ref delta, sci.LineFromPosition(position))) + { + position += delta; + sci.SetSel(position, position); + lookupPosition += delta; + currentTarget = "IEventDispatcher(e.currentTarget)"; + } + if (currentTarget.Length == 0 && ASContext.CommonSettings.GenerateScope && ctx.Features.ThisKey is not null) + currentTarget = ctx.Features.ThisKey; + if (currentTarget.Length > 0) currentTarget += "."; + var remove = $"{currentTarget}removeEventListener({eventName}, {handlerName});\n\t$(EntryPoint)"; + template = template.Replace("$(EntryPoint)", remove); + } + InsertCode(position, template, sci); + } + + protected static bool TryImportType(string type, ref int delta, int atLine) + { + var @class = ASContext.Context.ResolveType(type, ASContext.Context.CurrentModel); + if (@class.IsVoid()) return false; + delta += AddImportsByName(new List {type}, atLine); + return true; + } + + static string AddRemoveEvent(string eventName) { - foreach (string autoRemove in ASContext.CommonSettings.EventListenersAutoRemove) + foreach (var autoRemove in ASContext.CommonSettings.EventListenersAutoRemove) { - string test = autoRemove.Trim(); + var test = autoRemove.Trim(); if (test.Length == 0 || test.StartsWithOrdinal("//")) continue; - int colonPos = test.IndexOf(':'); + var colonPos = test.IndexOf(':'); if (colonPos >= 0) test = test.Substring(colonPos + 1); if (test != eventName) continue; return colonPos < 0 ? "" : autoRemove.Trim().Substring(0, colonPos); @@ -3909,227 +3566,166 @@ private static string AddRemoveEvent(string eventName) return null; } - private static void GenerateGetter(string name, MemberModel member, int position) => GenerateGetter(name, member, position, true, false); - - private static void GenerateGetter(string name, MemberModel member, int position, bool startsWithNewLine, bool endsWithNewLine) + static void GenerateGetter(string name, MemberModel member, int position) => GenerateGetter(name, member, position, true, false); + + protected static void GenerateGetter(string name, MemberModel member, int position, bool startsWithNewLine, bool endsWithNewLine) { var newMember = new MemberModel { Name = name, - Type = FormatType(member.Type), + Type = MemberModel.FormatType(GetShortType(member.Type)), Access = IsHaxe ? Visibility.Private : Visibility.Public }; if ((member.Flags & FlagType.Static) > 0) newMember.Flags = FlagType.Static; - string template = TemplateUtils.GetTemplate("Getter"); - string decl; - if (startsWithNewLine) decl = NewLine + TemplateUtils.ToDeclarationWithModifiersString(newMember, template); - else decl = TemplateUtils.ToDeclarationWithModifiersString(newMember, template); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Member", member.Name); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "BlankLine", NewLine); - if (endsWithNewLine) decl += NewLine + NewLine; - InsertCode(position, decl); - } - - private static void GenerateSetter(string name, MemberModel member, int position) - { + var template = TemplateUtils.GetTemplate("Getter"); + template = startsWithNewLine + ? NewLine + ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(newMember, template) + : ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(newMember, template); + template = TemplateUtils.ReplaceTemplateVariable(template, "Member", member.Name); + template = TemplateUtils.ReplaceTemplateVariable(template, "BlankLine", NewLine); + if (endsWithNewLine) template += NewLine + NewLine; + InsertCode(position, template); + } + + protected static void GenerateSetter(string name, MemberModel member, int position) + { var newMember = new MemberModel { Name = name, - Type = FormatType(member.Type), + Type = MemberModel.FormatType(GetShortType(member.Type)), Access = IsHaxe ? Visibility.Private : Visibility.Public - }; + }; if ((member.Flags & FlagType.Static) > 0) newMember.Flags = FlagType.Static; - string template = TemplateUtils.GetTemplate("Setter"); - string decl = NewLine + TemplateUtils.ToDeclarationWithModifiersString(newMember, template); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Member", member.Name); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Void", ASContext.Context.Features.voidKey ?? "void"); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "BlankLine", NewLine); - InsertCode(position, decl); - } - - private static void GenerateGetterSetter(string name, MemberModel member, int position) - { - string template = TemplateUtils.GetTemplate("GetterSetter"); - if (template == "") + var template = TemplateUtils.GetTemplate("Setter"); + template = NewLine + ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(newMember, template); + template = TemplateUtils.ReplaceTemplateVariable(template, "Member", member.Name); + template = TemplateUtils.ReplaceTemplateVariable(template, "Void", ASContext.Context.Features.voidKey ?? "void"); + template = TemplateUtils.ReplaceTemplateVariable(template, "BlankLine", NewLine); + InsertCode(position, template); + } + + protected static void GenerateGetterSetter(string name, MemberModel member, int position) + { + var template = TemplateUtils.GetTemplate("GetterSetter"); + if (template.Length == 0) { GenerateSetter(name, member, position); - ASContext.CurSciControl.SetSel(position, position); + PluginBase.MainForm.CurrentDocument?.SciControl.SetSel(position, position); GenerateGetter(name, member, position); return; - } + } var newMember = new MemberModel { Name = name, - Type = FormatType(member.Type), + Type = MemberModel.FormatType(GetShortType(member.Type)), Access = IsHaxe ? Visibility.Private : Visibility.Public - }; - if ((member.Flags & FlagType.Static) > 0) newMember.Flags = FlagType.Static; - string decl = NewLine + TemplateUtils.ToDeclarationWithModifiersString(newMember, template); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Member", member.Name); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "Void", ASContext.Context.Features.voidKey ?? "void"); - decl = TemplateUtils.ReplaceTemplateVariable(decl, "BlankLine", NewLine); - InsertCode(position, decl); - } - - private static string GetStaticKeyword(MemberModel member) - { - if ((member.Flags & FlagType.Static) > 0) return ASContext.Context.Features.staticKey ?? "static"; - return null; - } - - private static string GetPrivateAccessor(MemberModel member, ClassModel inClass) - { - string acc = GetStaticKeyword(member); - if (!string.IsNullOrEmpty(acc)) acc += " "; - return acc + GetPrivateKeyword(inClass); - } - - private static string GetPrivateKeyword(ClassModel inClass) + }; + if ((member.Flags & FlagType.Static) > 0) newMember.Flags = FlagType.Static; + template = NewLine + ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(newMember, template); + template = TemplateUtils.ReplaceTemplateVariable(template, "Member", member.Name); + template = TemplateUtils.ReplaceTemplateVariable(template, "Void", ASContext.Context.Features.voidKey ?? "void"); + template = TemplateUtils.ReplaceTemplateVariable(template, "BlankLine", NewLine); + InsertCode(position, template); + } + + static string GetStaticKeyword(MemberModel member) + { + if ((member.Flags & FlagType.Static) > 0) return ASContext.Context.Features.staticKey ?? "static"; + return null; + } + + static string GetPrivateAccessor(MemberModel member, MemberModel inClass) + { + var result = GetStaticKeyword(member); + if (!string.IsNullOrEmpty(result)) result += " "; + return result + GetPrivateKeyword(inClass); + } + + static string GetPrivateKeyword(MemberModel inClass) { if (GetDefaultVisibility(inClass) == Visibility.Protected) return ASContext.Context.Features.protectedKey ?? "protected"; return ASContext.Context.Features.privateKey ?? "private"; } - private static MemberModel GetLatestMemberForFunction(ClassModel inClass, Visibility funcVisi, MemberModel isStatic) + static MemberModel GetLatestMemberForFunction(ClassModel inClass, Visibility access, MemberModel isStatic) { - MemberModel latest = null; - if (isStatic != null && (isStatic.Flags & FlagType.Static) > 0) - { - latest = FindLatest(FlagType.Function | FlagType.Static, funcVisi, inClass); - if (latest == null) - { - latest = FindLatest(FlagType.Function | FlagType.Static, 0, inClass, true, false); - } - } - else - { - latest = FindLatest(FlagType.Function, funcVisi, inClass); - } - if (latest == null) - { - latest = FindLatest(FlagType.Function, 0, inClass, true, false); - } - if (latest == null) + MemberModel latest; + if (isStatic is not null && (isStatic.Flags & FlagType.Static) > 0) { - latest = FindLatest(FlagType.Function, 0, inClass, false, false); + latest = FindLatest(FlagType.Function | FlagType.Static, access, inClass) + ?? FindLatest(FlagType.Function | FlagType.Static, 0, inClass, true, false); } - return latest; + else latest = FindLatest(FlagType.Function, access, inClass); + return latest + ?? FindLatest(FlagType.Function, 0, inClass, true, false) + ?? FindLatest(FlagType.Function, 0, inClass, false, false); } - private static MemberModel GetLatestMemberForVariable(GeneratorJobType job, ClassModel inClass, Visibility varVisi, MemberModel isStatic) + static MemberModel GetLatestMemberForVariable(GeneratorJobType job, ClassModel inClass, Visibility access, MemberModel isStatic) { - MemberModel latest = null; + MemberModel latest; if (job.Equals(GeneratorJobType.Constant)) { - if ((isStatic.Flags & FlagType.Static) > 0) - { - latest = FindLatest(FlagType.Constant | FlagType.Static, varVisi, inClass); - } - else - { - latest = FindLatest(FlagType.Constant, varVisi, inClass); - } - if (latest == null) - { - latest = FindLatest(FlagType.Constant, 0, inClass, true, false); - } + latest = ((isStatic.Flags & FlagType.Static) > 0 + ? FindLatest(FlagType.Constant | FlagType.Static, access, inClass) + : FindLatest(FlagType.Constant, access, inClass)) + ?? FindLatest(FlagType.Constant, 0, inClass, true, false); } else { - if ((isStatic.Flags & FlagType.Static) > 0) - { - latest = FindLatest(FlagType.Variable | FlagType.Static, varVisi, inClass); - if (latest == null) - { - latest = FindLatest(FlagType.Variable | FlagType.Static, 0, inClass, true, false); - } - } - else - { - latest = FindLatest(FlagType.Variable, varVisi, inClass); - } - } - if (latest == null) - { - latest = FindLatest(FlagType.Variable, varVisi, inClass, false, false); - } - return latest; - } - - private static MemberModel FindMember(string name, ClassModel inClass) - { - MemberList list; - if (inClass == ClassModel.VoidClass) - list = ASContext.Context.CurrentModel.Members; - else list = inClass.Members; - - MemberModel found = null; - foreach (MemberModel member in list) - { - if (member.Name == name) - { - found = member; - break; - } + latest = (isStatic.Flags & FlagType.Static) > 0 + ? FindLatest(FlagType.Variable | FlagType.Static, access, inClass) ?? FindLatest(FlagType.Variable | FlagType.Static, 0, inClass, true, false) + : FindLatest(FlagType.Variable, access, inClass); } - return found; + return latest ?? FindLatest(FlagType.Variable, access, inClass, false, false); } - private static MemberModel FindLatest(FlagType match, ClassModel inClass) - { - return FindLatest(match, 0, inClass); - } + static MemberModel FindLatest(FlagType match, ClassModel inClass) => FindLatest(match, 0, inClass); - private static MemberModel FindLatest(FlagType match, Visibility visi, ClassModel inClass) - { - return FindLatest(match, visi, inClass, true, true); - } + static MemberModel FindLatest(FlagType match, Visibility access, ClassModel inClass) => FindLatest(match, access, inClass, true, true); - private static MemberModel FindLatest(FlagType match, Visibility visi, ClassModel inClass, bool isFlagMatchStrict, bool isVisibilityMatchStrict) + protected static MemberModel FindLatest(FlagType match, Visibility access, ClassModel inClass, bool isFlagMatchStrict, bool isVisibilityMatchStrict) { - MemberList list; - if (inClass == ClassModel.VoidClass) - list = ASContext.Context.CurrentModel.Members; - else - list = inClass.Members; + var list = inClass == ClassModel.VoidClass + ? ASContext.Context.CurrentModel.Members + : inClass.Members; MemberModel latest = null; MemberModel fallback = null; - foreach (MemberModel member in list) + foreach (var member in list) { fallback = member; if (isFlagMatchStrict && isVisibilityMatchStrict) { - if ((member.Flags & match) == match && (visi == 0 || (member.Access & visi) == visi)) + if ((member.Flags & match) == match && (access == 0 || (member.Access & access) == access)) { latest = member; } } else if (isFlagMatchStrict) { - if ((member.Flags & match) == match && (visi == 0 || (member.Access & visi) > 0)) + if ((member.Flags & match) == match && (access == 0 || (member.Access & access) > 0)) { latest = member; } } else if (isVisibilityMatchStrict) { - if ((member.Flags & match) > 0 && (visi == 0 || (member.Access & visi) == visi)) + if ((member.Flags & match) > 0 && (access == 0 || (member.Access & access) == access)) { latest = member; } } else { - if ((member.Flags & match) > 0 && (visi == 0 || (member.Access & visi) > 0)) + if ((member.Flags & match) > 0 && (access == 0 || (member.Access & access) > 0)) { latest = member; } } } - if (isFlagMatchStrict || isVisibilityMatchStrict) - fallback = null; + if (isFlagMatchStrict || isVisibilityMatchStrict) fallback = null; return latest ?? fallback; } @@ -4144,6 +3740,15 @@ static void AddExplicitScopeReference(ScintillaControl sci, ClassModel inClass, sci.ReplaceSel(text); UpdateLookupPosition(position, text.Length - length); } + + protected virtual MemberModel ToParameterVar(FunctionParameter member) + { + var type = member.paramType.Length > member.paramQualType.Length ? member.paramType : member.paramQualType; + return new MemberModel(AvoidKeyword(member.paramName), GetShortType(type), FlagType.ParameterVar, 0); + } + + protected virtual string ToDeclarationWithModifiersString(MemberModel member, string template) => TemplateUtils.ToDeclarationWithModifiersString(member, template); + #endregion #region override generator @@ -4153,84 +3758,26 @@ static void AddExplicitScopeReference(ScintillaControl sci, ClassModel inClass, /// /// Don't keep the list open if the word does not match /// Completion was handled - protected virtual bool HandleOverrideCompletion(bool autoHide) - { - // explore members - IASContext ctx = ASContext.Context; - ClassModel curClass = ctx.CurrentClass; - if (curClass.IsVoid()) return false; - - List members = new List(); - curClass.ResolveExtends(); // Resolve inheritance chain - - // explore getters or setters - FlagType mask = FlagType.Function | FlagType.Getter | FlagType.Setter; - ClassModel tmpClass = curClass.Extends; - Visibility acc = ctx.TypesAffinity(curClass, tmpClass); - while (tmpClass != null && !tmpClass.IsVoid()) - { - if (tmpClass.QualifiedName.StartsWithOrdinal("flash.utils.Proxy")) - { - foreach (MemberModel member in tmpClass.Members) - { - member.Namespace = "flash_proxy"; - members.Add(member); - } - break; - } - else - { - foreach (MemberModel member in tmpClass.Members) - { - if (curClass.Members.Search(member.Name, FlagType.Override, 0) != null) continue; - var parameters = member.Parameters; - if ((member.Flags & FlagType.Dynamic) > 0 - && (member.Access & acc) > 0 - && ((member.Flags & FlagType.Function) > 0 - || ((member.Flags & mask) > 0 && (!IsHaxe || parameters[0].Name == "get" || parameters[1].Name == "set")))) - { - members.Add(member); - } - } - - tmpClass = tmpClass.Extends; - // members visibility - acc = ctx.TypesAffinity(curClass, tmpClass); - } - } - members.Sort(); - - // build list - var known = new List(); - MemberModel last = null; - foreach (MemberModel member in members) - { - if (last == null || last.Name != member.Name) - known.Add(new MemberItem(member)); - last = member; - } - if (known.Count > 0) CompletionList.Show(known, autoHide); - return true; - } + protected virtual bool HandleOverrideCompletion(bool autoHide) => ASContext.Context.CodeComplete.HandleOverrideCompletion(string.Empty, autoHide); - public static void GenerateOverride(ScintillaControl Sci, ClassModel ofClass, MemberModel member, int position) + public static void GenerateOverride(ScintillaControl sci, ClassModel ofClass, MemberModel member, int position) { - var context = ASContext.Context; - var features = context.Features; - List typesUsed = new List(); - bool isProxy = (member.Namespace == "flash_proxy"); + var ctx = ASContext.Context; + var features = ctx.Features; + var typesUsed = new List(); + var isProxy = member.Namespace == "flash_proxy"; if (isProxy) typesUsed.Add("flash.utils.flash_proxy"); - int line = Sci.LineFromPosition(position); - string currentText = Sci.GetLine(line); - int startPos = currentText.Length; + var line = sci.LineFromPosition(position); + var currentText = sci.GetLine(line); + var startPos = currentText.Length; GetStartPos(currentText, ref startPos, features.privateKey); GetStartPos(currentText, ref startPos, features.protectedKey); GetStartPos(currentText, ref startPos, features.internalKey); GetStartPos(currentText, ref startPos, features.publicKey); GetStartPos(currentText, ref startPos, features.staticKey); GetStartPos(currentText, ref startPos, features.overrideKey); - startPos += Sci.PositionFromLine(line); + startPos += sci.PositionFromLine(line); var newMember = new MemberModel { @@ -4241,263 +3788,170 @@ public static void GenerateOverride(ScintillaControl Sci, ClassModel ofClass, Me newMember.Namespace = member.Namespace; else newMember.Access = member.Access; - bool isAS2Event = context.Settings.LanguageId == "AS2" && member.Name.StartsWithOrdinal("on"); - if (!isAS2Event && ofClass.QualifiedName != "Object") newMember.Flags |= FlagType.Override; - - string decl = ""; - - FlagType flags = member.Flags; + var isAS2Event = ctx.Settings.LanguageId == "AS2" && member.Name.StartsWithOrdinal("on"); + if (!isAS2Event && ofClass.QualifiedName != "Object") newMember.Flags |= FlagType.Override; + string declaration; + var flags = member.Flags; if ((flags & FlagType.Static) > 0) newMember.Flags |= FlagType.Static; var parameters = member.Parameters; if ((flags & (FlagType.Getter | FlagType.Setter)) > 0) { if (IsHaxe) newMember.Access = Visibility.Private; var type = newMember.Type; - var name = newMember.Name; - if (parameters != null && parameters.Count == 1) type = parameters[0].Type; - type = FormatType(type); - if (type == null && !features.hasInference) type = features.objectKey; + if (parameters is not null && parameters.Count == 1 && parameters[0].Type is not null) type = parameters[0].Type; + type = MemberModel.FormatType(type); + if (type is null && !features.hasInference) type = features.objectKey; newMember.Type = type; - var currentClass = context.CurrentClass; - if (ofClass.Members.Search(name, FlagType.Getter, 0) != null - && (!IsHaxe || (parameters?[0].Name == "get" && currentClass.Members.Search($"get_{name}", FlagType.Function, 0) == null))) - { - var template = TemplateUtils.GetTemplate("OverrideGetter", "Getter"); - template = TemplateUtils.ToDeclarationWithModifiersString(newMember, template); - template = TemplateUtils.ReplaceTemplateVariable(template, "Member", $"super.{name}"); - decl += template; - } - if (ofClass.Members.Search(name, FlagType.Setter, 0) != null - && (!IsHaxe || (parameters?[1].Name == "set" && currentClass.Members.Search($"set_{name}", FlagType.Function, 0) == null))) - { - var template = TemplateUtils.GetTemplate("OverrideSetter", "Setter"); - template = TemplateUtils.ToDeclarationWithModifiersString(newMember, template); - template = TemplateUtils.ReplaceTemplateVariable(template, "Member", $"super.{name}"); - template = TemplateUtils.ReplaceTemplateVariable(template, "Void", features.voidKey ?? "void"); - if (decl.Length > 0) template = "\n\n" + template.Replace("$(EntryPoint)", ""); - decl += template; - } - decl = TemplateUtils.ReplaceTemplateVariable(decl, "BlankLine", ""); + declaration = ((ASGenerator) ctx.CodeGenerator).TryGetOverrideGetterTemplate(ofClass, parameters, newMember); + var set = ((ASGenerator) ctx.CodeGenerator).TryGetOverrideSetterTemplate(ofClass, parameters, newMember); + if (set.Length > 0 && declaration.Length > 0) set = "\n\n" + set.Replace("$(EntryPoint)", ""); + declaration += set; + declaration = TemplateUtils.ReplaceTemplateVariable(declaration, "BlankLine", ""); typesUsed.Add(type); } else { - var type = FormatType(newMember.Type); - var noRet = type == null || type.Equals("void", StringComparison.OrdinalIgnoreCase); - type = (noRet && type != null) ? features.voidKey : type; + var type = MemberModel.FormatType(newMember.Type); + var noRet = type is null || type.Equals("void", StringComparison.OrdinalIgnoreCase); + type = (noRet && type is not null) ? features.voidKey : type; if (!noRet) typesUsed.Add(type); newMember.Template = member.Template; newMember.Type = type; // fix parameters if needed - if (parameters != null) - foreach (MemberModel para in parameters) + if (parameters is not null) + foreach (var para in parameters) if (para.Type == "any") para.Type = "*"; newMember.Parameters = parameters; - var action = (isProxy || isAS2Event) ? "" : GetSuperCall(member, typesUsed); + var action = isProxy || isAS2Event ? "" : GetSuperCall(member, typesUsed); var template = TemplateUtils.GetTemplate("MethodOverride"); - template = TemplateUtils.ToDeclarationWithModifiersString(newMember, template); + template = ((ASGenerator) ctx.CodeGenerator).ToDeclarationWithModifiersString(newMember, template); template = TemplateUtils.ReplaceTemplateVariable(template, "Method", action); - decl = template; + declaration = template; } - - Sci.BeginUndoAction(); + sci.BeginUndoAction(); try { - if (context.Settings.GenerateImports && typesUsed.Count > 0) + if (ctx.Settings.GenerateImports && typesUsed.Count > 0) { var types = GetQualifiedTypes(typesUsed, ofClass.InFile); - int offset = AddImportsByName(types, line); + var offset = AddImportsByName(types, line); position += offset; startPos += offset; } - - Sci.SetSel(startPos, position + member.Name.Length); - InsertCode(startPos, decl, Sci); + sci.SetSel(startPos, position + member.Name.Length); + InsertCode(startPos, declaration, sci); } - finally { Sci.EndUndoAction(); } + finally { sci.EndUndoAction(); } + } + + protected virtual string TryGetOverrideGetterTemplate(ClassModel ofClass, List parameters, MemberModel newMember) + { + var name = newMember.Name; + if (!ofClass.Members.Contains(name, FlagType.Getter)) return string.Empty; + var result = TemplateUtils.GetTemplate("OverrideGetter", "Getter"); + result = ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(newMember, result); + result = TemplateUtils.ReplaceTemplateVariable(result, "Member", $"super.{name}"); + return result; + } + + protected virtual string TryGetOverrideSetterTemplate(ClassModel ofClass, List parameters, MemberModel newMember) + { + var name = newMember.Name; + if (!ofClass.Members.Contains(name, FlagType.Setter)) return string.Empty; + var result = TemplateUtils.GetTemplate("OverrideSetter", "Setter"); + result = ((ASGenerator) ASContext.Context.CodeGenerator).ToDeclarationWithModifiersString(newMember, result); + result = TemplateUtils.ReplaceTemplateVariable(result, "Member", $"super.{name}"); + result = TemplateUtils.ReplaceTemplateVariable(result, "Void", ASContext.Context.Features.voidKey ?? "void"); + return result; } - public static void GenerateDelegateMethods(ScintillaControl sci, MemberModel member, - Dictionary selectedMembers, ClassModel classModel, ClassModel inClass) + public static void GenerateDelegateMethods(ScintillaControl sci, MemberModel member, Dictionary selectedMembers, ClassModel classModel, ClassModel inClass) { + var ctx = ASContext.Context; + var generateImports = ctx.Settings.GenerateImports; sci.BeginUndoAction(); try { - string result = TemplateUtils.ReplaceTemplateVariable( - TemplateUtils.GetTemplate("DelegateMethodsHeader"), - "Class", - classModel.Type); - - int position = -1; - List importsList = new List(); - bool isStaticMember = (member.Flags & FlagType.Static) > 0; - + var result = TemplateUtils.GetTemplate("DelegateMethodsHeader"); + result = TemplateUtils.ReplaceTemplateVariable(result, "Class", classModel.Type); + var position = -1; + var importsList = new List(); + var isStaticMember = (member.Flags & FlagType.Static) > 0; inClass.ResolveExtends(); - - Dictionary.KeyCollection selectedMemberKeys = selectedMembers.Keys; - foreach (MemberModel m in selectedMemberKeys) + foreach (var m in selectedMembers.Keys) { - MemberModel mCopy = (MemberModel) m.Clone(); - - string methodTemplate = NewLine; - - bool overrideFound = false; - ClassModel baseClassType = inClass; - while (baseClassType != null && !baseClassType.IsVoid()) - { - MemberList inClassMembers = baseClassType.Members; - foreach (MemberModel inClassMember in inClassMembers) - { - if ((inClassMember.Flags & FlagType.Function) > 0 - && m.Name.Equals(inClassMember.Name)) - { - mCopy.Flags |= FlagType.Override; - overrideFound = true; - break; - } - } - - if (overrideFound) - break; - - baseClassType = baseClassType.Extends; - } - + var mCopy = m.Clone(); + var methodTemplate = NewLine; + var baseClassType = inClass; + if (baseClassType.ContainsMember(m.Name, FlagType.Function, true)) + mCopy.Flags |= FlagType.Override; var flags = m.Flags; if (isStaticMember && (flags & FlagType.Static) == 0) mCopy.Flags |= FlagType.Static; var variableTemplate = string.Empty; - if (IsHaxe & (flags & (FlagType.Getter | FlagType.Setter)) != 0) - { - variableTemplate = NewLine + NewLine + (TemplateUtils.GetStaticExternOverride(m) + TemplateUtils.GetModifiers(m)).Trim() + " var " + m.Name; - } - if ((flags & FlagType.Getter) > 0) - { - if (!IsHaxe || (m.Parameters[0].Name != "null" && m.Parameters[0].Name != "never")) - { - string modifiers; - if (IsHaxe) - { - variableTemplate += "(get, "; - modifiers = (TemplateUtils.GetStaticExternOverride(m) + TemplateUtils.GetModifiers(Visibility.Private)).Trim(); - } - else modifiers = (TemplateUtils.GetStaticExternOverride(m) + TemplateUtils.GetModifiers(m)).Trim(); - methodTemplate += TemplateUtils.GetTemplate("Getter"); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Modifiers", modifiers); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Name", m.Name); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "EntryPoint", ""); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Type", FormatType(m.Type)); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Member", member.Name + "." + m.Name); - flags &= ~FlagType.Function; - } - else variableTemplate += "(" + m.Parameters[0].Name + ", "; - } - if ((flags & FlagType.Setter) > 0) - { - if (!IsHaxe || (m.Parameters[1].Name != "null" && m.Parameters[1].Name != "never")) - { - string modifiers; - string type; - if (IsHaxe) - { - variableTemplate += "set)"; - if (methodTemplate != NewLine) methodTemplate += NewLine; - modifiers = (TemplateUtils.GetStaticExternOverride(m) + TemplateUtils.GetModifiers(Visibility.Private)).Trim(); - type = FormatType(m.Type); - } - else - { - modifiers = (TemplateUtils.GetStaticExternOverride(m) + TemplateUtils.GetModifiers(m)).Trim(); - type = m.Parameters[0].Type; - } - methodTemplate += TemplateUtils.GetTemplate("Setter"); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Modifiers", modifiers); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Name", m.Name); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "EntryPoint", ""); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Type", type); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Member", member.Name + "." + m.Name); - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Void", ASContext.Context.Features.voidKey ?? "void"); - flags &= ~FlagType.Function; - } - else variableTemplate += m.Parameters[1].Name + ")"; - } - if (!string.IsNullOrEmpty(variableTemplate)) - { - variableTemplate += ":" + m.Type + ";"; - result += variableTemplate; - } + ((ASGenerator) ctx.CodeGenerator).TryGetGetterSetterDelegateTemplate(member, m, ref flags, ref variableTemplate, ref methodTemplate); + if (!string.IsNullOrEmpty(variableTemplate)) result += variableTemplate + ":" + m.Type + ";"; if ((flags & FlagType.Function) > 0) { methodTemplate += TemplateUtils.GetTemplate("Function"); methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Body", "<<$(Return) >>$(Body)"); methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "EntryPoint", null); - methodTemplate = TemplateUtils.ToDeclarationWithModifiersString(mCopy, methodTemplate); - if (m.Type != null && m.Type.ToLower() != "void") + methodTemplate = ((ASGenerator) ctx.CodeGenerator).ToDeclarationWithModifiersString(mCopy, methodTemplate); + if (m.Type is not null && m.Type.ToLower() != "void") methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Return", "return"); else methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Return", null); // check for varargs - bool isVararg = false; - if (m.Parameters != null && m.Parameters.Count > 0) + var isVararg = false; + if (!m.Parameters.IsNullOrEmpty()) { - MemberModel mm = m.Parameters[m.Parameters.Count - 1]; + var mm = m.Parameters[m.Parameters.Count - 1]; if (mm.Name.StartsWithOrdinal("...")) isVararg = true; } - string callMethodTemplate = TemplateUtils.GetTemplate("CallFunction"); + var callMethodTemplate = TemplateUtils.GetTemplate("CallFunction"); if (!isVararg) { callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Name", member.Name + "." + m.Name); - callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Arguments", - TemplateUtils.CallParametersString(m)); + callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Arguments", TemplateUtils.CallParametersString(m)); callMethodTemplate += ";"; } else { - List pseudoParamsList = new List(); - pseudoParamsList.Add(new MemberModel("null", null, FlagType.ParameterVar, 0)); - pseudoParamsList.Add(new MemberModel("[$(Subarguments)].concat($(Lastsubargument))", null, FlagType.ParameterVar, 0)); - MemberModel pseudoParamsOwner = new MemberModel(); - pseudoParamsOwner.Parameters = pseudoParamsList; - - callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Name", - member.Name + "." + m.Name + ".apply"); - callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Arguments", - TemplateUtils.CallParametersString(pseudoParamsOwner)); + var pseudoParamsList = new List + { + new MemberModel("null", null, FlagType.ParameterVar, 0), + new MemberModel("[$(Subarguments)].concat($(Lastsubargument))", null, FlagType.ParameterVar, 0) + }; + var pseudoParamsOwner = new MemberModel {Parameters = pseudoParamsList}; + callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Name", member.Name + "." + m.Name + ".apply"); + callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Arguments", TemplateUtils.CallParametersString(pseudoParamsOwner)); callMethodTemplate += ";"; - List arrayParamsList = new List(); + var arrayParamsList = new List(); for (int i = 0; i < m.Parameters.Count - 1; i++) { - MemberModel param = m.Parameters[i]; + var param = m.Parameters[i]; arrayParamsList.Add(param); } - pseudoParamsOwner.Parameters = arrayParamsList; - - callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Subarguments", - TemplateUtils.CallParametersString(pseudoParamsOwner)); - - callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Lastsubargument", - m.Parameters[m.Parameters.Count - 1].Name.TrimStart('.', ' ')); + callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Subarguments", TemplateUtils.CallParametersString(pseudoParamsOwner)); + callMethodTemplate = TemplateUtils.ReplaceTemplateVariable(callMethodTemplate, "Lastsubargument", m.Parameters[m.Parameters.Count - 1].Name.TrimStart('.', ' ')); } - methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Body", callMethodTemplate); } methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "BlankLine", NewLine); result += methodTemplate; - - if (ASContext.Context.Settings.GenerateImports && m.Parameters != null) + if (generateImports && m.Parameters is not null) { - importsList.AddRange(from param in m.Parameters where param.Type != null select param.Type); + importsList.AddRange(from param in m.Parameters where param.Type is not null select param.Type); } - if (position < 0) { - MemberModel latest = GetLatestMemberForFunction(inClass, mCopy.Access, mCopy); - if (latest == null) + var latest = GetLatestMemberForFunction(inClass, mCopy.Access, mCopy); + if (latest is null) { position = sci.WordStartPosition(sci.CurrentPos, true); sci.SetSel(position, sci.WordEndPosition(position, true)); @@ -4509,89 +3963,114 @@ public static void GenerateDelegateMethods(ScintillaControl sci, MemberModel mem } } else position = sci.CurrentPos; - - if (ASContext.Context.Settings.GenerateImports && m.Type != null) importsList.Add(m.Type); + if (generateImports && m.Type is not null) importsList.Add(m.Type); } - - if (ASContext.Context.Settings.GenerateImports && importsList.Count > 0 && position > -1) + if (generateImports && importsList.Count > 0 && position > -1) { var types = GetQualifiedTypes(importsList, inClass.InFile); position += AddImportsByName(types, sci.LineFromPosition(position)); sci.SetSel(position, position); } - InsertCode(position, result, sci); } finally { sci.EndUndoAction(); } } - private static void GetStartPos(string currentText, ref int startPos, string keyword) + protected virtual void TryGetGetterSetterDelegateTemplate(MemberModel member, MemberModel receiver, ref FlagType flags, ref string variableTemplate, ref string methodTemplate) { - if (keyword == null) return; - int p = currentText.IndexOfOrdinal(keyword); - if (p > 0 && p < startPos) startPos = p; + if ((flags & FlagType.Getter) != 0) + { + var modifiers = (TemplateUtils.GetStaticExternOverride(receiver) + TemplateUtils.GetModifiers(receiver)).Trim(); + methodTemplate += TemplateUtils.GetTemplate("Getter"); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Modifiers", modifiers); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Name", receiver.Name); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "EntryPoint", ""); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Type", MemberModel.FormatType(receiver.Type)); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Member", member.Name + "." + receiver.Name); + flags &= ~FlagType.Function; + } + if ((flags & FlagType.Setter) != 0) + { + var modifiers = (TemplateUtils.GetStaticExternOverride(receiver) + TemplateUtils.GetModifiers(receiver)).Trim(); + methodTemplate += TemplateUtils.GetTemplate("Setter"); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Modifiers", modifiers); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Name", receiver.Name); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "EntryPoint", ""); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Type", receiver.Parameters[0].Type); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Member", member.Name + "." + receiver.Name); + methodTemplate = TemplateUtils.ReplaceTemplateVariable(methodTemplate, "Void", ASContext.Context.Features.voidKey ?? "void"); + flags &= ~FlagType.Function; + } } - private static string GetShortType(string type) + static void GetStartPos(string currentText, ref int startPos, string keyword) { - return string.IsNullOrEmpty(type) ? type : Regex.Replace(type, @"(?=\w+\.<)|(?:\w+\.)", string.Empty); + if (keyword is null) return; + var p = currentText.IndexOfOrdinal(keyword); + if (p > 0 && p < startPos) startPos = p; } - private static string FormatType(string type) + static readonly Regex reShortType = new Regex(@"(?=\w+\.<)|(?:\w+\.)"); + + protected static string GetShortType(string type) { + if (string.IsNullOrEmpty(type)) return type; + if (!type.Contains('@') && type.LastIndexOf('.') is { } startIndex && startIndex != -1) + { + var importName = type.Substring(startIndex + 1); + var imports = ASContext.Context.ResolveImports(ASContext.Context.CurrentModel); + if (imports.Count == 0) imports = ASContext.Context.CurrentModel.Imports; + if (!imports.Any(it => it.Name == importName && it.Type != type)) + type = reShortType.Replace(type, string.Empty); + } + else type = reShortType.Replace(type, string.Empty); return MemberModel.FormatType(type); } - private static string CleanType(string type) + static string CleanType(string type) { - if (string.IsNullOrEmpty(type)) - { - return type; - } - int p = type.IndexOf('$'); + if (string.IsNullOrEmpty(type)) return type; + var p = type.IndexOf('$'); if (p > 0) type = type.Substring(0, p); p = type.IndexOf('<'); if (p > 1 && type[p - 1] == '.') p--; if (p > 0) type = type.Substring(0, p); p = type.IndexOf('@'); - if (p > 0) - { - type = type.Substring(0, p); - } + if (p > 0) type = type.Substring(0, p); return type; } - private static string GetSuperCall(MemberModel member, List typesUsed) + static string GetSuperCall(MemberModel member, ICollection typesUsed) { - string args = ""; - if (member.Parameters != null) - foreach (MemberModel param in member.Parameters) + var args = ""; + if (member.Parameters is not null) + foreach (var param in member.Parameters) { if (param.Name.StartsWith('.')) break; args += ", " + TemplateUtils.GetParamName(param); AddTypeOnce(typesUsed, param.Type); } - bool noRet = string.IsNullOrEmpty(member.Type) || member.Type.Equals("void", StringComparison.OrdinalIgnoreCase); + var noRet = string.IsNullOrEmpty(member.Type) || member.Type.Equals("void", StringComparison.OrdinalIgnoreCase); if (!noRet) AddTypeOnce(typesUsed, member.Type); - string action = ""; + var result = ""; if ((member.Flags & FlagType.Function) > 0) { - action = + result = (noRet ? "" : "return ") + "super." + member.Name + ((args.Length > 2) ? "(" + args.Substring(2) + ")" : "()") + ";"; } else if ((member.Flags & FlagType.Setter) > 0 && args.Length > 0) { - action = "super." + member.Name + " = " + member.Parameters[0].Name + ";"; + result = "super." + member.Name + " = " + member.Parameters[0].Name + ";"; } else if ((member.Flags & FlagType.Getter) > 0) { - action = "return super." + member.Name + ";"; + result = "return super." + member.Name + ";"; } - return action; + return result; } #endregion @@ -4604,21 +4083,20 @@ private static string GetSuperCall(MemberModel member, List typesUsed) /// Types to import if needed /// Current line in editor /// Inserted characters count - private static int AddImportsByName(IEnumerable typesUsed, int atLine) + protected static int AddImportsByName(IEnumerable typesUsed, int atLine) { - int length = 0; - IASContext context = ASContext.Context; + var length = 0; + var context = ASContext.Context; var addedTypes = new HashSet(); typesUsed = context.DecomposeTypes(typesUsed); - foreach (string type in typesUsed) + foreach (var type in typesUsed) { var cleanType = CleanType(type); - if (string.IsNullOrEmpty(cleanType) || addedTypes.Contains(cleanType) || cleanType.IndexOf('.') <= 0) + if (string.IsNullOrEmpty(cleanType) || addedTypes.Contains(cleanType) || !cleanType.Contains('.')) continue; addedTypes.Add(cleanType); - MemberModel import = new MemberModel(cleanType.Substring(cleanType.LastIndexOf('.') + 1), cleanType, FlagType.Import, Visibility.Public); - if (!context.IsImported(import, atLine)) - length += InsertImport(import, false); + var import = new MemberModel(cleanType.Substring(cleanType.LastIndexOf('.') + 1), cleanType, FlagType.Import, Visibility.Public); + if (!context.IsImported(import, atLine)) length += InsertImport(import, false); } return length; } @@ -4631,27 +4109,24 @@ private static int AddImportsByName(IEnumerable typesUsed, int atLine) /// Inserted characters count public static int InsertImport(MemberModel member, bool fixScrolling) { - ScintillaControl sci = ASContext.CurSciControl; - FileModel cFile = ASContext.Context.CurrentModel; - int position = sci.CurrentPos; - int curLine = sci.LineFromPosition(position); - - string fullPath = member.Type; + var fullPath = member.Type; if ((member.Flags & (FlagType.Class | FlagType.Enum | FlagType.TypeDef | FlagType.Struct)) > 0) - { - FileModel inFile = member.InFile; - if (inFile != null && inFile.Module == member.Name && inFile.Package != "") + { + var inFile = member.InFile; + if (inFile is not null && inFile.Module == member.Name && inFile.Package != "") fullPath = inFile.Package + "." + inFile.Module; fullPath = CleanType(fullPath); } - string nl = LineEndDetector.GetNewLineMarker(sci.EOLMode); - string statement = "import " + fullPath + ";" + nl; - - // locate insertion point - int line = (ASContext.Context.InPrivateSection) ? cFile.PrivateSectionIndex : 0; - if (cFile.InlinedRanges != null) + var sci = PluginBase.MainForm.CurrentDocument.SciControl; + var newLineMarker = LineEndDetector.GetNewLineMarker(sci.EOLMode); + var statement = "import " + fullPath + ";" + newLineMarker; + var position = sci.CurrentPos; + var curLine = sci.LineFromPosition(position); + var cFile = ASContext.Context.CurrentModel; + var line = (ASContext.Context.InPrivateSection) ? cFile.PrivateSectionIndex : 0; + if (cFile.InlinedRanges is not null) { - foreach (InlineRange range in cFile.InlinedRanges) + foreach (var range in cFile.InlinedRanges) { if (position > range.Start && position < range.End) { @@ -4660,52 +4135,55 @@ public static int InsertImport(MemberModel member, bool fixScrolling) } } } - int firstLine = line; - bool found = false; - int packageLine = -1; - int indent = 0; - int skipIfDef = 0; - var importComparer = new CaseSensitiveImportComparer(); + var firstLine = line; + var found = false; + var packageLine = -1; + var indent = 0; + var skipIfDef = 0; while (line < curLine) { var txt = sci.GetLine(line++).TrimStart(); - if (txt.StartsWith("package")) - { - packageLine = line; - firstLine = line; - } - // skip Haxe #if blocks - else if (txt.StartsWithOrdinal("#if ") && txt.IndexOfOrdinal("#end") < 0) skipIfDef++; - else if (skipIfDef > 0) - { - if (txt.StartsWithOrdinal("#end")) skipIfDef--; - else continue; - } + if (packageLine != -2 && txt.StartsWith("package")) + { + packageLine = line; + firstLine = line; + } + // skip Haxe #if blocks + else if (txt.StartsWithOrdinal("#if ") && !txt.Contains("#end")) skipIfDef++; + else if (skipIfDef > 0) + { + if (txt.StartsWithOrdinal("#end")) skipIfDef--; + else continue; + } // insert imports after a package declaration else if (txt.Length > 6 && txt.StartsWithOrdinal("import") && txt[6] <= 32) - { - packageLine = -1; - found = true; - indent = sci.GetLineIndentation(line - 1); - // insert in alphabetical order - var mImport = ASFileParserRegexes.Import.Match(txt); - if (mImport.Success && importComparer.Compare(mImport.Groups["package"].Value, fullPath) > 0) - { - line--; - break; - } - } - else if (found) - { - line--; - break; + { + packageLine = -2; + found = true; + indent = sci.GetLineIndentation(line - 1); + // insert in alphabetical order + var mImport = ASFileParserRegexes.Import.Match(txt); + if (mImport.Success && CaseSensitiveImportComparer.CompareImports(mImport.Groups["package"].Value, fullPath) > 0) + { + line--; + break; + } + } + else if (found) + { + line--; + break; } - if (packageLine >= 0 && !IsHaxe && txt.IndexOf('{') >= 0) + if (packageLine >= 0) { - packageLine = -1; - indent = sci.GetLineIndentation(line - 1) + PluginBase.MainForm.Settings.IndentSize; - firstLine = line; + if (IsHaxe) packageLine = -2; + else if (txt.Contains('{')) + { + packageLine = -2; + indent = sci.GetLineIndentation(line - 1) + PluginBase.Settings.IndentSize; + firstLine = line; + } } } @@ -4717,20 +4195,18 @@ public static int InsertImport(MemberModel member, bool fixScrolling) sci.ReplaceSel(statement); sci.SetLineIndentation(line, indent); sci.LineScroll(0, firstLine - sci.FirstVisibleLine + 1); - - ASContext.Context.RefreshContextCache(fullPath); + + ASContext.Context.RefreshContextCache(fullPath); return sci.GetLine(line).Length; } #endregion #region common safe code insertion - static private int lookupPosition; - - public static void InsertCode(int position, string src) - { - InsertCode(position, src, ASContext.CurSciControl); - } - + + protected static int lookupPosition; + + public static void InsertCode(int position, string src) => InsertCode(position, src, PluginBase.MainForm.CurrentDocument?.SciControl); + public static void InsertCode(int position, string src, ScintillaControl sci) { sci.BeginUndoAction(); @@ -4749,78 +4225,68 @@ public static void InsertCode(int position, string src, ScintillaControl sci) /// /// Order declaration modifiers /// - private static string FixModifiersLocation(string src, string[] modifierOrder) - { - bool needUpdate = false; - string[] lines = src.Split('\n'); - for (int i = 0; i < lines.Length; i++) - { - string line = lines[i]; - - Match m = reModifiers.Match(line); - if (!m.Success) continue; - - Group decl = m.Groups[2]; - string modifiers = decl.Value; - string before = "", after = ""; - bool insertAfter = false; - - for (int j = 0; j < modifierOrder.Length; j++) - { - string modifier = modifierOrder[j]; - if (modifier == GeneralSettings.DECLARATION_MODIFIER_REST) insertAfter = true; - else - { - modifier = RemoveAndExtractModifier(modifier, ref modifiers); - if (insertAfter) after += modifier; - else before += modifier; - } - } - - modifiers = before + modifiers + after; - - if (decl.Value != modifiers) - { - lines[i] = line.Remove(decl.Index, decl.Length).Insert(decl.Index, modifiers); - needUpdate = true; + static string FixModifiersLocation(string src, string[] modifierOrder) + { + var needUpdate = false; + var lines = src.Split('\n'); + for (var i = 0; i < lines.Length; i++) + { + var line = lines[i]; + var m = reModifiers.Match(line); + if (!m.Success) continue; + + Group decl = m.Groups[2]; + string modifiers = decl.Value; + string before = "", after = ""; + bool insertAfter = false; + + foreach (var it in modifierOrder) + { + if (it == GeneralSettings.DECLARATION_MODIFIER_REST) insertAfter = true; + else + { + var modifier = RemoveAndExtractModifier(it, ref modifiers); + if (insertAfter) after += modifier; + else before += modifier; + } + } + + modifiers = before + modifiers + after; + + if (decl.Value != modifiers) + { + lines[i] = line.Remove(decl.Index, decl.Length).Insert(decl.Index, modifiers); + needUpdate = true; } } return needUpdate ? string.Join("\n", lines) : src; } - private static string RemoveAndExtractModifier(string modifier, ref string modifiers) - { - modifier += " "; - int index = modifiers.IndexOf(modifier, StringComparison.Ordinal); - - if (index == -1) return null; - modifiers = modifiers.Remove(index, modifier.Length); - return modifier; + static string RemoveAndExtractModifier(string modifier, ref string modifiers) + { + modifier += " "; + var index = modifiers.IndexOfOrdinal(modifier); + if (index == -1) return null; + modifiers = modifiers.Remove(index, modifier.Length); + return modifier; } - private static void UpdateLookupPosition(int position, int delta) + protected static void UpdateLookupPosition(int position, int delta) { - if (lookupPosition > position) - { - if (lookupPosition < position + delta) lookupPosition = position;// replaced text at cursor position - else lookupPosition += delta; - } + if (lookupPosition <= position) return; + if (lookupPosition < position + delta) lookupPosition = position;// replaced text at cursor position + else lookupPosition += delta; } - private static void AddLookupPosition() - { - AddLookupPosition(ASContext.CurSciControl); - } + static void AddLookupPosition() => AddLookupPosition(PluginBase.MainForm.CurrentDocument?.SciControl); - private static void AddLookupPosition(ScintillaControl sci) + protected static void AddLookupPosition(ScintillaControl sci) { - if (lookupPosition >= 0 && sci != null) - { - int lookupLine = sci.LineFromPosition(lookupPosition); - int lookupCol = lookupPosition - sci.PositionFromLine(lookupLine); - // TODO: Refactor, doesn't make a lot of sense to have this feature inside the Panel - ASContext.Panel.SetLastLookupPosition(sci.FileName, lookupLine, lookupCol); - } + if (lookupPosition < 0 || sci is null) return; + var lookupLine = sci.LineFromPosition(lookupPosition); + var lookupCol = lookupPosition - sci.PositionFromLine(lookupLine); + // TODO: Refactor, doesn't make a lot of sense to have this feature inside the Panel + ASContext.Panel.SetLastLookupPosition(sci.FileName, lookupLine, lookupCol); } #endregion @@ -4830,90 +4296,90 @@ private static void AddLookupPosition(ScintillaControl sci) /// /// Available generators /// - public enum GeneratorJobType:int + public enum GeneratorJobType : long { - GetterSetter, - Getter, - Setter, - ComplexEvent, - BasicEvent, - Delegate, - Variable, - Function, - ImplementInterface, - PromoteLocal, - MoveLocalUp, - AddImport, - Class, - FunctionPublic, - VariablePublic, - Constant, - Constructor, - ToString, - FieldFromParameter, - AddInterfaceDef, - ConvertToConst, - AddAsParameter, - ChangeMethodDecl, - EventMetatag, - AssignStatementToVar, - ChangeConstructorDecl, + GetterSetter = 1, + Getter = 1 << 1, + Setter = 1 << 2, + ComplexEvent = 1 << 3, + BasicEvent = 1 << 4, + Delegate = 1 << 5, + Variable = 1 << 6, + Function = 1 << 7, + ImplementInterface = 1 << 8, + PromoteLocal = 1 << 9, + MoveLocalUp = 1 << 10, + AddImport = 1 << 11, + Class = 1 << 12, + FunctionPublic = 1 << 13, + VariablePublic = 1 << 14, + Constant = 1 << 15, + Constructor = 1 << 16, + ToString = 1 << 17, + FieldFromParameter = 1 << 18, + AddInterfaceDef = 1 << 19, + ConvertToConst = 1 << 20, + AddAsParameter = 1 << 21, + ChangeMethodDecl = 1 << 22, + EventMetatag = 1 << 23, + AssignStatementToVar = 1 << 24, + ChangeConstructorDecl = 1 << 25, + Interface = 1 << 26, + User = 1 << 27, } /// /// Generation completion list item /// - class GeneratorItem : ICompletionListItem + public class GeneratorItem : ICompletionListItem { - private string label; - internal GeneratorJobType job { get; } - private MemberModel member; - private ClassModel inClass; - private Object data; + internal GeneratorJobType Job { get; } + readonly MemberModel member; + readonly ClassModel inClass; + readonly Action action; - public GeneratorItem(string label, GeneratorJobType job, MemberModel member, ClassModel inClass) + public GeneratorItem(string label, GeneratorJobType job, Action action) : this(label, job, action, null) { - this.label = label; - this.job = job; - this.member = member; - this.inClass = inClass; } - public GeneratorItem(string label, GeneratorJobType job, MemberModel member, ClassModel inClass, Object data) : this(label, job, member, inClass) + public GeneratorItem(string label, GeneratorJobType job, Action action, object data) { - this.data = data; + Label = label; + Job = job; + this.action = action; + Data = data; } - public string Label - { - get { return label; } - } - public string Description + public GeneratorItem(string label, GeneratorJobType job, MemberModel member, ClassModel inClass) : this(label, job, member, inClass, null) { - get { return TextHelper.GetString("Info.GeneratorTemplate"); } } - public Bitmap Icon + public GeneratorItem(string label, GeneratorJobType job, MemberModel member, ClassModel inClass, object data) { - get { return (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_DECLARATION); } + Label = label; + Job = job; + this.member = member; + this.inClass = inClass; + Data = data; } + public string Label { get; } + + public string Description => TextHelper.GetString("Info.GeneratorTemplate"); + + public Bitmap Icon => (Bitmap)ASContext.Panel.GetIcon(PluginUI.ICON_DECLARATION); + public string Value { get { - ASGenerator.GenerateJob(job, member, inClass, label, data); + if (action is not null) action(); + else ASGenerator.GenerateJob(Job, member, inClass, Label, Data); return null; } } - public Object Data - { - get - { - return data; - } - } + public object Data { get; } } public class FoundDeclaration @@ -4937,7 +4403,7 @@ public class FunctionParameter public FunctionParameter(string parameter, string paramType, string paramQualType, ASResult result) { - this.paramName = parameter; + paramName = parameter; this.paramType = paramType; this.paramQualType = paramQualType; this.result = result; @@ -4946,17 +4412,16 @@ public FunctionParameter(string parameter, string paramType, string paramQualTyp class StatementReturnType { - public ASResult resolve; - public Int32 position; - public String word; + public readonly ASResult Resolve; + public readonly int Position; + public readonly string Word; - public StatementReturnType(ASResult resolve, Int32 position, String word) + public StatementReturnType(ASResult resolve, int position, string word) { - this.resolve = resolve; - this.position = position; - this.word = word; + Resolve = resolve; + Position = position; + Word = word; } } #endregion -} - +} \ No newline at end of file diff --git a/External/Plugins/ASCompletion/Completion/ArgumentsProcessor.cs b/External/Plugins/ASCompletion/Completion/ArgumentsProcessor.cs index b857f2f836..ddc3ec5131 100644 --- a/External/Plugins/ASCompletion/Completion/ArgumentsProcessor.cs +++ b/External/Plugins/ASCompletion/Completion/ArgumentsProcessor.cs @@ -5,30 +5,20 @@ namespace ASCompletion.Completion { public class ArgumentsProcessor { - static public string Process(string text, Hashtable variables) - { - ArgumentsProcessor proc = new ArgumentsProcessor(); - proc.variables = variables; - return proc.Run(text); - } - - /* PRIVATE */ - - static private Regex re_Argument = + static readonly Regex re_Argument = new Regex("\\$\\((?[a-z]+)\\)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - private Hashtable variables; + public static string Process(string text, Hashtable variables) => new ArgumentsProcessor {variables = variables}.Run(text); - private string Run(string text) - { - return re_Argument.Replace(text, new MatchEvaluator(Lookup)); - } + Hashtable variables; + + string Run(string text) => re_Argument.Replace(text, Lookup); - private string Lookup(Match m) + string Lookup(Match m) { - string name = m.Groups["name"].Value; + var name = m.Groups["name"].Value; if (variables.ContainsKey(name)) return (string)variables[name]; - else return m.Value; + return m.Value; } } } diff --git a/External/Plugins/ASCompletion/Completion/Brace.cs b/External/Plugins/ASCompletion/Completion/Brace.cs index bdbfc26275..5e7ab19cfb 100644 --- a/External/Plugins/ASCompletion/Completion/Brace.cs +++ b/External/Plugins/ASCompletion/Completion/Brace.cs @@ -1,5 +1,7 @@ using System; using System.Text.RegularExpressions; +using PluginCore; +using Array = System.Array; namespace ASCompletion.Completion { @@ -9,47 +11,47 @@ namespace ASCompletion.Completion [Serializable] public sealed class Brace { - private string name; - private char open; - private char close; - private bool addSpace; - private bool ignoreWhitespace; - private Rule[] rules; + string name; + char open; + char close; + bool addSpace; + bool ignoreWhitespace; + Rule[] rules; public string Name { - get { return name; } - set { name = value; } + get => name; + set => name = value; } public char Open { - get { return open; } - set { open = value; } + get => open; + set => open = value; } public char Close { - get { return close; } - set { close = value; } + get => close; + set => close = value; } public bool AddSpace { - get { return addSpace; } - set { addSpace = value; } + get => addSpace; + set => addSpace = value; } public bool IgnoreWhitespace { - get { return ignoreWhitespace; } - set { ignoreWhitespace = value; } + get => ignoreWhitespace; + set => ignoreWhitespace = value; } public Rule[] Rules { - get { return rules; } - set { rules = value ?? new Rule[0]; } + get => rules; + set => rules = value ?? Array.Empty(); } /// @@ -70,9 +72,9 @@ public Brace(string name, char open, char close, bool addSpace, bool ignoreWhite /// public bool ShouldOpen(char charBefore, byte styleBefore, char charAfter, byte styleAfter) { - for (int i = 0; i < rules.Length; i++) + foreach (var it in rules) { - if (rules[i].Matches(charBefore, styleBefore, charAfter, styleAfter)) + if (it.Matches(charBefore, styleBefore, charAfter, styleAfter)) { return true; } @@ -107,15 +109,15 @@ public override string ToString() [Serializable] public sealed class Rule { - private bool notAfterChars; - private Regex afterChars; - private bool notAfterStyles; - private Style[] afterStyles; - private bool notBeforeChars; - private Regex beforeChars; - private bool notBeforeStyles; - private Style[] beforeStyles; - private Logic logic; + bool notAfterChars; + Regex afterChars; + bool notAfterStyles; + Style[] afterStyles; + bool notBeforeChars; + Regex beforeChars; + bool notBeforeStyles; + Style[] beforeStyles; + Logic logic; public Rule() { @@ -145,108 +147,86 @@ public Rule(bool? notAfterChars, string afterChars, bool? notAfterStyles, Style[ public bool NotAfterChars { - get { return notAfterChars; } - set { notAfterChars = value; } + get => notAfterChars; + set => notAfterChars = value; } public string AfterChars { - get { return FromRegex(afterChars); } - set { afterChars = ToRegex(value); } + get => FromRegex(afterChars); + set => afterChars = ToRegex(value); } public bool NotAfterStyles { - get { return notAfterStyles; } - set { notAfterStyles = value; } + get => notAfterStyles; + set => notAfterStyles = value; } public Style[] AfterStyles { - get { return afterStyles ?? new Style[0]; } - set { afterStyles = value == null || value.Length == 0 ? null : value; } + get => afterStyles ?? Array.Empty