-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: AssemblyDefinitionSettingsProvider
- Loading branch information
1 parent
d86b1dc
commit 79a2f15
Showing
7 changed files
with
804 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
207 changes: 207 additions & 0 deletions
207
...SettingsProvider/AssemblyDefinitionSettingsProvider.ImplicitAssemblyReferenceProcessor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/** Assembly Definitions Manager for Project Settings Panel | ||
** (c) 2024 https://github.com/sator-imaging | ||
** Licensed under the MIT License | ||
*/ | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
using UnityEditor; | ||
using UnityEditorInternal; | ||
using UnityEngine; | ||
|
||
#nullable enable | ||
|
||
namespace SatorImaging.UnityFundamentals.Editor | ||
{ | ||
partial class AssemblyDefinitionSettingsProvider | ||
{ | ||
public sealed class ImplicitAssemblyReferenceProcessor : AssetPostprocessor | ||
{ | ||
const string LOG_PREFIX = "[" + nameof(ImplicitAssemblyReferenceProcessor) + "] "; | ||
|
||
|
||
/// <summary>Get or set processing order. Smaller value to be invoked earlier.</summary> | ||
public int PostprocessOrder { get; set; } = 0; | ||
|
||
public override int GetPostprocessOrder() => PostprocessOrder; | ||
|
||
|
||
/* preprocess ================================================================ */ | ||
|
||
// be static. not sure whether processing is done by one instance or multiple instances | ||
readonly static HashSet<string> _processedFilePathSet = new(); | ||
|
||
public void OnPreprocessAsset() | ||
{ | ||
if (assetImporter is not AssemblyDefinitionImporter) | ||
return; | ||
|
||
if (!Prefs.Instance.EnableImplicitRefsOnChanges) | ||
return; | ||
|
||
// avoid unexpected loop | ||
if (!_processedFilePathSet.Add(assetPath)) | ||
{ | ||
//Debug.Log(LOG_PREFIX + "already processed: " + assetPath); | ||
return; | ||
} | ||
|
||
ResetIntegratedInspector(); | ||
LockIntegratedInspector(true); | ||
if (!TryAddImplicitReferences(assetPath)) | ||
{ | ||
// don't require. domain reloading will happen by asset import --> LockIntegratedInspector(false); | ||
} | ||
} | ||
|
||
|
||
/* internals ================================================================ */ | ||
|
||
static StringBuilder? cache_sb; | ||
|
||
public static bool TryAddImplicitReferences(string filePath) | ||
{ | ||
if (!File.Exists(filePath)) | ||
return false; | ||
|
||
if (!filePath.StartsWith(ASSETS_DIR_SLASH)) | ||
return false; | ||
|
||
var jsonText = File.ReadAllText(filePath, Encoding.UTF8); | ||
var jsonObj = JsonUtility.FromJson<AssemDef_JsonLoader>(jsonText); | ||
var name = jsonObj?.name | ||
?? throw new NotSupportedException("no assembly name: " + filePath); | ||
var prefs = Prefs.Instance; | ||
|
||
// don't modify implicit refs source | ||
if (!(prefs.ImplicitReferenceNames?.Length > 0) || prefs.ImplicitReferenceNames.Contains(name, StringComparer.OrdinalIgnoreCase)) | ||
return false; | ||
|
||
bool isGuidMode = true == jsonObj.references?.FirstOrDefault()?.StartsWith(GUID_MODE_PREFIX, StringComparison.OrdinalIgnoreCase); | ||
var implicitRefs = (isGuidMode ? prefs.ImplicitReferenceGUIDs : prefs.ImplicitReferenceNames).AsEnumerable(); | ||
|
||
if (jsonObj.references != null) | ||
{ | ||
implicitRefs = implicitRefs | ||
.Where(x => !jsonObj.references.Contains(x, StringComparer.OrdinalIgnoreCase)) // ignore case for safe | ||
; | ||
} | ||
|
||
if (!implicitRefs.Any()) | ||
{ | ||
return false; | ||
} | ||
|
||
SPECIAL_CASE_FOR_NEWLY_CREATED_FILE: | ||
var pos_references = jsonText.AsSpan().IndexOf(JSON_REFS_INSERT_POSITION_FINDER, StringComparison.Ordinal); | ||
if (pos_references < 0) | ||
{ | ||
// NOTE: newly created .asmdef has only "name" property. ie. has no ',' | ||
if (jsonText.Contains(',')) | ||
{ | ||
Debug.LogWarning(LOG_PREFIX + "no references property: " + jsonText); | ||
return false; | ||
} | ||
|
||
jsonText = jsonText.AsSpan().TrimEnd()[..^1].TrimEnd().ToString().Replace("\t", JSON_INDENT) | ||
+ "," + Environment.NewLine + JSON_REFS_INSERT_POSITION_FINDER + "]" + Environment.NewLine + '}'; | ||
goto SPECIAL_CASE_FOR_NEWLY_CREATED_FILE; | ||
} | ||
|
||
pos_references += JSON_REFS_INSERT_POSITION_FINDER.Length; | ||
|
||
var sb = (cache_sb ??= new()); | ||
sb.Append(jsonText.AsSpan(0, pos_references)); | ||
sb.Append(JSON_REFS_ARRAY_ITEM_OPEN.AsSpan()); | ||
sb.AppendJoin(JSON_REFS_ARRAY_ITEM_CLOSE, implicitRefs); | ||
sb.Append('"'); // don't forget closing quote. opening quote is included in ITEM OPEN/CLOSE | ||
if (jsonText[pos_references] != ']') | ||
{ | ||
if (jsonObj.references?.Length > 0) | ||
sb.Append(','); | ||
} | ||
else | ||
{ | ||
sb.AppendLine(); | ||
sb.Append(JSON_INDENT.AsSpan()); | ||
} | ||
sb.Append(jsonText.AsSpan(pos_references)); | ||
|
||
var result = sb.ToString(); | ||
sb.Length = 0; // don't clear to keep allocated buffer! | ||
|
||
File.WriteAllText(filePath, result, Encoding.UTF8); | ||
//AssetDatabase.ImportAsset(filePath); | ||
|
||
Debug.Log(LOG_PREFIX + filePath + "...\n" + result); | ||
|
||
return true; | ||
} | ||
|
||
|
||
readonly static Regex re_emptyRef = new(@"^\s+"""",?[\r\n]+", RegexOptions.Compiled | RegexOptions.Multiline); | ||
|
||
public static bool TryRemoveImplicitReferences(string filePath) | ||
{ | ||
if (!File.Exists(filePath)) | ||
return false; | ||
|
||
if (!filePath.StartsWith(ASSETS_DIR_SLASH)) | ||
return false; | ||
|
||
// try remove both guid and name | ||
var implicitRefs = Prefs.Instance.ImplicitReferenceGUIDs?.Concat(Prefs.Instance.ImplicitReferenceNames); | ||
if (implicitRefs == null) | ||
return false; | ||
|
||
var contentSpan = File.ReadAllText(filePath, Encoding.UTF8).ToCharArray().AsSpan(); | ||
var originalLength = contentSpan.Length; | ||
|
||
// NOTE: remove only references entries | ||
int pos_references = ((ReadOnlySpan<char>)contentSpan).IndexOf(JSON_REFS_INSERT_POSITION_FINDER, StringComparison.Ordinal); | ||
if (pos_references < 0) | ||
return false; | ||
|
||
int len_references = contentSpan.Slice(pos_references).IndexOf(']'); | ||
if (len_references < 0) | ||
return false; | ||
|
||
var consumed = contentSpan.Length; | ||
int pos; | ||
foreach (var item in implicitRefs) | ||
{ | ||
// not sure why implicit cast operator doesn't work | ||
while ((pos = ((ReadOnlySpan<char>)contentSpan).Slice(pos_references, len_references).IndexOf(item, StringComparison.Ordinal)) >= 0) | ||
{ | ||
pos += pos_references; | ||
contentSpan.Slice(pos + item.Length).CopyTo(contentSpan.Slice(pos)); | ||
|
||
consumed -= item.Length; | ||
len_references -= item.Length; | ||
} | ||
} | ||
|
||
if (originalLength == consumed) | ||
{ | ||
return false; | ||
} | ||
|
||
var result = contentSpan.Slice(0, consumed).ToString(); | ||
result = re_emptyRef.Replace(result, string.Empty); | ||
|
||
File.WriteAllText(filePath, result, Encoding.UTF8); | ||
//AssetDatabase.ImportAsset(filePath); | ||
|
||
Debug.Log(LOG_PREFIX + filePath + "...\n" + result); | ||
|
||
return true; | ||
} | ||
|
||
} | ||
|
||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...ngsProvider/AssemblyDefinitionSettingsProvider.ImplicitAssemblyReferenceProcessor.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
72 changes: 72 additions & 0 deletions
72
Editor/AssemblyDefinitionSettingsProvider/AssemblyDefinitionSettingsProvider.Prefs.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/** Assembly Definitions Manager for Project Settings Panel | ||
** (c) 2024 https://github.com/sator-imaging | ||
** Licensed under the MIT License | ||
*/ | ||
|
||
using System; | ||
using System.IO; | ||
using System.Text; | ||
using System.Threading; | ||
using UnityEngine; | ||
|
||
#nullable enable | ||
|
||
namespace SatorImaging.UnityFundamentals.Editor | ||
{ | ||
partial class AssemblyDefinitionSettingsProvider | ||
{ | ||
[Serializable] | ||
public sealed class Prefs | ||
{ | ||
// json fields | ||
[SerializeField] bool enableImplicitRefsOnChanges = false; | ||
[SerializeField] bool turnOnImplicitRefsOnChangesAfterDomainReloading = false; | ||
[SerializeField] string[]? implicitReferenceGUIDs; | ||
[SerializeField] string[]? implicitReferenceNames; | ||
|
||
//properties | ||
/// <summary></summary> | ||
/// <value></value> | ||
public string[]? ImplicitReferenceNames | ||
{ | ||
get { return implicitReferenceNames; } | ||
set { implicitReferenceNames = value; } | ||
} | ||
|
||
public string[]? ImplicitReferenceGUIDs | ||
{ | ||
get { return implicitReferenceGUIDs; } | ||
set { implicitReferenceGUIDs = value; } | ||
} | ||
|
||
public bool EnableImplicitRefsOnChanges | ||
{ | ||
get { return enableImplicitRefsOnChanges; } | ||
set { enableImplicitRefsOnChanges = value; } | ||
} | ||
|
||
public bool TurnOnImplicitRefsOnChangesAfterDomainReloading | ||
{ | ||
get { return turnOnImplicitRefsOnChangesAfterDomainReloading; } | ||
set { turnOnImplicitRefsOnChangesAfterDomainReloading = value; } | ||
} | ||
|
||
|
||
// export path | ||
readonly static string OUTPUT_PATH = Application.dataPath | ||
+ "/../ProjectSettings/" + nameof(AssemblyDefinitionSettingsProvider) + ".json"; | ||
|
||
private Prefs() | ||
{ | ||
if (File.Exists(OUTPUT_PATH)) | ||
JsonUtility.FromJsonOverwrite(File.ReadAllText(OUTPUT_PATH, Encoding.UTF8), this); | ||
} | ||
|
||
volatile static Prefs? _instance; | ||
public static Prefs Instance => _instance ?? Interlocked.CompareExchange(ref _instance, new(), null) ?? _instance; | ||
|
||
public void Save() => File.WriteAllText(OUTPUT_PATH, JsonUtility.ToJson(this, true), Encoding.UTF8); | ||
} | ||
|
||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
Editor/AssemblyDefinitionSettingsProvider/AssemblyDefinitionSettingsProvider.Prefs.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.