1616
1717internal class PackageManagerReadmeExtension : IPackageManagerExtension
1818{
19- private TextElement detailContainer ;
2019 private TextSettings textSettings ;
21-
20+
2221 public void OnPackageSelected ( PackageInfo packageInfo ) => EditorApplication . delayCall += ( ) => InjectReadmeIntoPackageManager ( packageInfo ) ;
2322
2423 public void OnPackageSelectionChange ( PackageInfo packageInfo ) => EditorApplication . delayCall += ( ) => InjectReadmeIntoPackageManager ( packageInfo ) ;
@@ -34,122 +33,122 @@ private void InjectReadmeIntoPackageManager(PackageInfo packageInfo)
3433
3534 var packageManagerWindow = windows [ 0 ] ; // Assuming the first found window is the one we want
3635
37- // Navigate the visual tree to find the “descriptionTab” or equivalent via reflection
36+ // Navigate the visual tree to find the "detailDescription" via reflection
3837 var rootVisualElementProperty = packageManagerWindowType . GetProperty ( "rootVisualElement" , BindingFlags . Public | BindingFlags . Instance ) ;
3938 if ( rootVisualElementProperty == null ) return ;
4039
4140 if ( rootVisualElementProperty . GetValue ( packageManagerWindow ) is not VisualElement rootVisualElement ) return ;
4241
43- detailContainer = rootVisualElement . Query < TextElement > ( "detailDescription" ) . First ( ) ; // this one is a text element
44-
42+ var detailContainer = rootVisualElement . Q < TextElement > ( "detailDescription" ) ;
43+
4544 if ( detailContainer == null ) return ;
46- if ( packageInfo == null ) return ;
47- if ( string . IsNullOrEmpty ( packageInfo . resolvedPath ) ) return ;
48-
49- detailContainer . Clear ( ) ;
50- detailContainer . text = "" ;
51-
52- var files = Directory . EnumerateFiles ( packageInfo . resolvedPath , "*.md" , SearchOption . AllDirectories ) . ToArray ( ) ;
53- var file = files . FirstOrDefault ( f => Path . GetFileName ( f ) is "README.md" or "index.md" ) ;
54- if ( string . IsNullOrEmpty ( file ) ) file = files . FirstOrDefault ( ) ;
55- var description = string . IsNullOrEmpty ( file ) ? "README.md not found." : File . ReadAllText ( file ) ;
56-
57- var text = description + "\n \n " + packageInfo . description ;
58- // LogUnicodePoints(text);
59- text = ReplaceUnicodeBeforeFE0FWithMap ( text ) ;
60-
61- var x = GenerateVisualElement ( text , link => LinkHandler ( link , file ) , true , file ) ;
62- // document = rootVisualElement.visualTreeAssetSource.stylesheets.FirstOrDefault().
63- // document.panelSettings = Resources.Load<PanelSettings>("Panel Settings");
64- // Debug.Log(document.panelSettings != null);
65- // document.panelSettings.textSettings.fallbackSpriteAssets = new List<SpriteAsset> { Resources.Load<SpriteAsset>("Sprite Assets/emoji_sheet") };
66- // Debug.Log("UI Document: " + document);
67- textSettings = Resources . Load < TextSettings > ( "Text Settings" ) ;
68- // textSettings.set
69- // detailContainer.
70- detailContainer . Add ( x ) ;
45+
46+ var parentElement = detailContainer . parent ;
47+ var markdownContainer = parentElement . Q < VisualElement > ( null , "md-container" ) ;
48+
49+ // Remove existing markdown container if it exists
50+ markdownContainer ? . RemoveFromHierarchy ( ) ;
51+
52+ // If packageInfo is null or the resolved path is not set, exit
53+ if ( packageInfo == null || string . IsNullOrEmpty ( packageInfo . resolvedPath ) ) return ;
54+
55+ // Find markdown files in the package's resolved path
56+ var markdownFiles = Directory . EnumerateFiles ( packageInfo . resolvedPath , "*.md" , SearchOption . AllDirectories ) . ToArray ( ) ;
57+ var readmeFilePath = markdownFiles . FirstOrDefault ( f => Path . GetFileName ( f ) == "README.md" || Path . GetFileName ( f ) == "index.md" )
58+ ?? markdownFiles . FirstOrDefault ( ) ;
59+
60+ // Set the content of the detail container
61+ var readmeContent = string . IsNullOrEmpty ( readmeFilePath ) ? "README.md not found." : File . ReadAllText ( readmeFilePath ) ;
62+ // string combinedText = $"{readmeContent}\n\n{packageInfo.description}";
63+ var combinedText = $ "{ readmeContent } \n \n "; // Only show the README.md content since the package description is still existing
64+
65+ // Possibly do some preprocessing on the text here
66+ combinedText = ReplaceUnicodeBeforeFE0FWithMap ( combinedText ) ;
67+
68+ // Generate a new VisualElement with the markdown and add it to the parent element
69+ var markdownVisualElement = GenerateVisualElement ( combinedText , link => LinkHandler ( link , readmeFilePath ) , true , readmeFilePath ) ;
70+ markdownVisualElement . AddToClassList ( "md-container" ) ;
71+
72+ // Insert the new VisualElement before the detailContainer
73+ parentElement . Insert ( parentElement . IndexOf ( detailContainer ) , markdownVisualElement ) ;
7174 }
72-
75+
7376 private void LogUnicodePoints ( string input )
7477 {
75- foreach ( char c in input )
78+ foreach ( var c in input )
7679 {
7780 if ( $ "{ ( int ) c : X4} " == "FE0F" )
7881 {
7982 break ;
8083 // Debug.Log(((int)c).ToString("X"));
8184 }
85+
8286 Debug . Log ( $ "Char: { c } , Unicode: { ( int ) c : X4} ") ;
8387 }
8488 }
85-
86- public static string RemoveUnicodeFE0F ( string input )
87- {
88- return input . Replace ( "\uFE0F " , string . Empty ) ;
89- }
89+
90+ public static string RemoveUnicodeFE0F ( string input ) => input . Replace ( "\uFE0F " , string . Empty ) ;
9091
9192 public static string ReplaceUnicode ( string input )
9293 {
93- string output = string . Empty ;
94- char previous = char . MinValue ;
95- foreach ( char c in input )
94+ var output = string . Empty ;
95+ var previous = char . MinValue ;
96+ foreach ( var c in input )
9697 {
9798 if ( c == '\uFE0F ' )
9899 {
99100 var code = char . ConvertToUtf32 ( previous . ToString ( ) , 0 ) . ToString ( "X" ) ;
100101 code = code . Replace ( "B" , "b" ) ;
101- string prefix = "" ;
102- for ( int i = 0 ; i < 4 - code . Length ; i ++ )
103- {
102+ var prefix = "" ;
103+ for ( var i = 0 ; i < 4 - code . Length ; i ++ )
104104 prefix += 0 ;
105- }
106105
107106 code = prefix + code ;
108107 code += "-fe0f" ;
109108 var tag = $ "<sprite name=\" { code } \" >";
110- tag = $ "<sprite name=\" 0023\" >";
109+ tag = "<sprite name=\" 0023\" >" ;
111110 tag = @"\u20E3" ;
112- output += tag ;
111+ output += tag ;
113112 Debug . Log ( tag ) ;
114113 }
115114 else
116- {
117115 output += c ;
118- }
116+
119117 previous = c ;
120118 }
121119
122120 return output ;
123121 }
124-
122+
125123 public static string ReplaceUnicodeBeforeFE0F ( string input )
126124 {
127125 // Pattern to match any character followed by the Unicode FE0F
128126 // Using positive lookahead to not consume the FE0F in the match, enabling overlapping matches
129- string pattern = ".(?=\uFE0F )" ;
127+ var pattern = ".(?=\uFE0F )" ;
130128
131129 return Regex . Replace ( input , pattern , match =>
132130 {
133131 // Convert the matched character to its Unicode code point
134132 var codePoint = char . ConvertToUtf32 ( match . Value , 0 ) . ToString ( "X" ) ;
133+
135134 // Construct the replacement string with the Unicode value in the desired format
136135 return $ "<sprite={ codePoint } >";
137136 } ) . Replace ( "\uFE0F " , "" ) ; // Finally, remove all the FE0F occurrences
138137 }
139-
138+
140139 public static string ReplaceUnicodeBeforeFE0FWithMap ( string input )
141140 {
142- string pattern = ".(?=\uFE0F )" ;
143-
141+ var pattern = ".(?=\uFE0F )" ;
142+
144143 return Regex . Replace ( input , pattern , match =>
145144 {
146145 // Convert the matched character to its Unicode code point in hexadecimal format
147146 var codePointHex = char . ConvertToUtf32 ( match . Value , 0 ) . ToString ( "X4" ) ;
147+
148148 // Check if the map contains the code point and use the mapped value if available
149- if ( map . TryGetValue ( codePointHex , out var spriteIndex ) )
150- {
149+ if ( map . TryGetValue ( codePointHex , out var spriteIndex ) )
151150 return $ "<sprite={ spriteIndex } >";
152- }
151+
153152 // Fallback to the original match if no mapping exists
154153 return match . Value ;
155154 } ) . Replace ( "\uFE0F " , "" ) ; // Finally, remove all the FE0F occurrences
@@ -198,54 +197,55 @@ public static string ReplaceUnicodeBeforeFE0FWithMap(string input)
198197 // // This nuanced approach aims to balance between correct display and clean text.
199198 // return result;
200199 // }
201-
202-
200+
203201
204202 private void LinkHandler ( string link , string path )
205203 {
206204 if ( link . EndsWith ( ".txt" ) || link . EndsWith ( ".md" ) )
207205 {
208206 link = Path . Combine ( Path . GetDirectoryName ( path ) ?? string . Empty , link ) ;
207+
209208 if ( ! File . Exists ( link ) ) return ;
210209 // Open file in explorer
211210 link = Path . GetFullPath ( link ) ; // Ensuring the path is absolute
212211 var args = $ "/select, \" { link } \" ";
213212 Process . Start ( "explorer.exe" , args ) ;
214213 }
215214 else
216- {
217215 Application . OpenURL ( link ) ;
218- }
219216 }
220217
221218 public VisualElement CreateExtensionUI ( ) => null ; // Not used in this workaround
222219
223220
224- public void OnPackageAddedOrUpdated ( PackageInfo packageInfo ) { }
221+ public void OnPackageAddedOrUpdated ( PackageInfo packageInfo )
222+ {
223+ }
224+
225+ public void OnPackageRemoved ( PackageInfo packageInfo )
226+ {
227+ }
228+
225229
226- public void OnPackageRemoved ( PackageInfo packageInfo ) { }
227-
228-
229-
230230 public static string ParseUnicodeToEmojiTag ( string input )
231231 {
232- string processedInput = string . Empty ;
233- foreach ( string unicode in ExtractUnicodeCodes ( input ) )
234- {
235- if ( map . TryGetValue ( unicode , out int spriteIndex ) )
236- {
232+ var processedInput = string . Empty ;
233+ foreach ( var unicode in ExtractUnicodeCodes ( input ) )
234+ if ( map . TryGetValue ( unicode , out var spriteIndex ) )
237235 processedInput += $ "<sprite={ spriteIndex } >";
238- }
239- }
236+
240237 return processedInput ;
241238 }
239+
242240 private static IEnumerable < string > ExtractUnicodeCodes ( string text )
243241 {
244242 var unicodeSymbols = text . Split ( '-' ) . Select ( code => code . Length > 4 ? code . Substring ( 0 , 4 ) : code ) ;
243+
245244 return unicodeSymbols . Where ( code => map . ContainsKey ( code ) ) ;
246245 }
247246
248- private static Dictionary < string , int > map = new ( ) {
247+ private static readonly Dictionary < string , int > map = new ( )
248+ {
249249 { "0023" , 0 } ,
250250 { "002A" , 1 } ,
251251 { "0030" , 2 } ,
@@ -260,89 +260,91 @@ private static IEnumerable<string> ExtractUnicodeCodes(string text)
260260 { "0039" , 11 } ,
261261 { "00A9" , 12 } ,
262262 { "00AE" , 13 } ,
263-
263+
264264 { "265F" , 3169 } , //
265-
265+
266266 { "2663" , 3171 } , //
267267 { "2665" , 3172 } , //
268268 { "2666" , 3673 } , //
269269 { "2668" , 3174 } , //
270270 { "267B" , 3175 } , //
271-
271+
272272 { "267E" , 3176 } , //
273-
273+
274274 { "2692" , 3178 } , //
275-
275+
276276 { "2694" , 3180 } , //
277277 { "2695" , 3181 } , //
278278 { "2696" , 3182 } , //
279279 { "2697" , 3183 } , //
280280 { "2699" , 3184 } , //
281281 { "269B" , 3185 } , //
282-
282+
283283 { "269C" , 3186 } , //
284284 { "26A0" , 3187 } , //
285285 { "26A7" , 3189 } , //
286-
286+
287287 { "26B0" , 3192 } , //
288288 { "26B1" , 3193 } , //
289-
290-
289+
290+
291291 { "26C8" , 3198 } , //
292-
292+
293293 { "26CF" , 3200 } , //
294294 { "26D1" , 3201 } , //
295295 { "26D3" , 3202 } , //
296296 { "26E9" , 3204 } , //
297297 { "26F0" , 3206 } , //
298298 { "26F1" , 3207 } , //
299-
299+
300300 { "26F4" , 3210 } , //
301301 { "26F7" , 3212 } , //
302302 { "26F8" , 3213 } , //
303303 { "26F9" , 3214 } , // has a lot of variants
304-
304+
305305 { "2708" , 3236 } , //
306306 { "2709" , 3237 } , //
307-
307+
308308 { "270C" , 3250 } , // has a lot of variants
309309 { "270D" , 3256 } , // has a lot of variants
310-
310+
311311 { "270F" , 3262 } , //
312312 { "2712" , 3263 } , //
313313 { "2714" , 3264 } , //
314314 { "2716" , 3265 } , //
315315 { "271D" , 3266 } , //
316316 { "2721" , 3267 } , //
317-
317+
318318 { "2733" , 3269 } , //
319319 { "2734" , 3770 } , //
320320 { "2744" , 3271 } , //
321321 { "2747" , 3272 } , //
322-
322+
323323 { "2763" , 3279 } , //
324-
324+
325325 { "2764" , 3280 } , //
326326 { "27A1" , 3284 } , //
327-
327+
328328 { "2934" , 3287 } , //
329329 { "2935" , 3288 } , //
330330 { "2B05" , 3289 } , //
331331 { "2B06" , 3290 } , //
332332 { "2B07" , 3291 } , //
333-
333+
334334 { "3030" , 3296 } , //
335335 { "303D" , 3297 } , //
336336 { "3297" , 3298 } , //
337337 { "3299" , 3299 } , //
338-
339- { "2660" , 3645 } , //
340-
338+
339+ { "2660" , 3645 } //
341340 } ;
342341}
343342
344343[ InitializeOnLoad ]
345344internal static class PackageManagerReadmeExtensionLoader
346345{
347- static PackageManagerReadmeExtensionLoader ( ) => PackageManagerExtensions . RegisterExtension ( new PackageManagerReadmeExtension ( ) ) ;
346+ static PackageManagerReadmeExtensionLoader ( )
347+ {
348+ PackageManagerExtensions . RegisterExtension ( new PackageManagerReadmeExtension ( ) ) ;
349+ }
348350}
0 commit comments