<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
Hi Christoph --<div><br></div><div>Sounds reasonable. Especially for comparison, right? Where else would you need a normalized path? User interface?</div><div><br></div><div>Is #forPathParts: a public or rather private interface? Maybe add commentary and change message category?</div><div><br></div><div>Best,</div><div>Marcel</div><div class="mb_sig"></div>
<blockquote class="history_container" type="cite" style="border-left-style: solid;border-width: 1px;margin-top: 20px;margin-left: 0px;padding-left: 10px;min-width: 500px">
<p style="color: #AAAAAA; margin-top: 10px;">Am 09.07.2022 19:56:59 schrieb christoph.thiede@student.hpi.uni-potsdam.de <christoph.thiede@student.hpi.uni-potsdam.de>:</p><div style="font-family:Arial,Helvetica,sans-serif">
<b>=============== Summary ===============</b><br>
<br>
Change Set: normalize-paths<br>
Date: 9 July 2022<br>
Author: Christoph Thiede<br>
<br>
Adds interface for path normalization on FileDirectory that removes path navigators such as <span style="color: #800080">'.'</span> or <span style="color: #800080">'..'</span>. Tests new <span style="color: #000080">#withNormalizedPath</span> for Windows and Unix file directories. Applies path normlization in file dialogs so that entering <span style="color: #800080">'../'</span> in the input field will trigger a correct selection of the parent node in the tree.<br>
<br>
<b>=============== Diff ===============</b><br>
<br>
<b>DosFileDirectory class>>forPathParts: {instance creation} · ct 7/9/2022 19:43</b><br>
<span style="color: #FF0000">+ forPathParts: pathParts<br>
+ <br>
+ | fileName partsStream |<br>
+ fileName := String streamContents: [:stream |<br>
+ partsStream := pathParts readStream.<br>
+ (self isDriveLetterRoot: partsStream peek)<br>
+ ifTrue: [stream nextPutAll: partsStream next]<br>
+ ifFalse: ["UNC path/network drive" stream nextPutAll: self slash].<br>
+ partsStream do: [:part |<br>
+ stream<br>
+ nextPutAll: self slash;<br>
+ nextPutAll: part]].<br>
+ ^ self on: fileName</span><br>
<br>
<b>DosFileDirectory class>>isDrive: {platform specific} · ct 7/9/2022 17:17 (changed)</b><br>
isDrive: fullName<br>
<s><span style="color: #0000FF">- "Answer whether the given full name describes a 'drive', e.g., one of the root directories of a Win32 file system. We allow two forms here - the classic one where a drive is specified by a letter followed by a colon, e.g., 'C:', 'D:' etc. and the network share form starting with double-backslashes e.g., '\\server'."<br>
- ^ (fullName size = 2 and: [fullName first isLetter and: [fullName last = $:]])<br>
- or: [(fullName beginsWith: '\\') and: [(fullName occurrencesOf: $\) = 2]]<br>
</span></s><span style="color: #FF0000">+ "Answer whether the given full name describes a 'drive', e.g., one of the root directories of a Win32 file system. We allow two forms here - the classic one where a drive is specified by a letter followed by a colon, e.g., 'C:', 'D:' etc., and the UNC/network share form starting with double-backslashes e.g., '\\server' or '\\localhost\c$\Users'."<br>
+ <br>
+ ^ (self isDriveLetterRoot: fullName)<br>
+ or: [self isUNCRoot: fullName]</span><br>
<br>
<b>DosFileDirectory class>>isDriveLetterRoot: {platform specific} · ct 7/9/2022 17:16</b><br>
<span style="color: #FF0000">+ isDriveLetterRoot: fullName<br>
+ "e.g., 'C:', 'D:' etc."<br>
+ <br>
+ ^ fullName size = 2 and: [fullName first isLetter] and: [fullName second = $:]</span><br>
<br>
<b>DosFileDirectory class>>isUNCRoot: {platform specific} · ct 7/9/2022 17:17</b><br>
<span style="color: #FF0000">+ isUNCRoot: fullName<br>
+ "e.g., '\\server' or '\\localhost\c$\Users'"<br>
+ <br>
+ ^ (fullName beginsWith: '\\') and: [(fullName occurrencesOf: $\) = 2]</span><br>
<br>
<b>DosFileDirectory>>withNormalizedPath {path access} · ct 7/9/2022 19:55</b><br>
<span style="color: #FF0000">+ withNormalizedPath<br>
+ "Answer a similar instance to the receiver with a normalized path, i.e., all path navigators such as . or .. will be eliminated."<br>
+ <br>
+ | normalizedParts originalParts |<br>
+ originalParts := self pathParts.<br>
+ normalizedParts := OrderedCollection new: originalParts size.<br>
+ originalParts do: [:part |<br>
+ part<br>
+ caseOf:<br>
+ {[self class parentDirectoryNickname] -><br>
+ [normalizedParts size > 1 ifTrue:<br>
+ [normalizedParts removeLast]].<br>
+ [self class currentDirectoryNickname] -> []}<br>
+ otherwise: [normalizedParts add: part]].<br>
+ ^ self class forPathParts: normalizedParts</span><br>
<br>
<b>DosFileDirectoryTests>>testWithNormalizedPath {tests} · ct 7/9/2022 19:41</b><br>
<span style="color: #FF0000">+ testWithNormalizedPath<br>
+ <br>
+ FileDirectory activeDirectoryClass == DosFileDirectory ifFalse:[^self].<br>
+ <br>
+ self assert: 'C:\plonk\griffle' equals: (FileDirectory on: 'C:\plonk\griffle') withNormalizedPath pathName.<br>
+ <br>
+ self assert: 'C:\plonk\griffle' equals: (FileDirectory on: 'C:\.\plonk\.\.\griffle\.\') withNormalizedPath pathName.<br>
+ self assert: 'C:\plonk\wiffy' equals: (FileDirectory on: 'C:\..\..\plonk\..\plonk\griffle\..\wiffy\ziffy\..') withNormalizedPath pathName.<br>
+ <br>
+ self assert: '\\share\ziffy' equals: (FileDirectory on: '\\share\..\plonk\..\ziffy') withNormalizedPath pathName.</span><br>
<br>
<b>FileAbstractSelectionDialog>>directory: {directory tree} · ct 7/9/2022 18:58 (changed)</b><br>
directory: aFileDirectory <br>
"Set the path of the directory to be displayed in the directory tree pane"<br>
<br>
<s><span style="color: #0000FF">- directory := aFileDirectory<br>
</span></s><span style="color: #FF0000">+ | normalizedDirectory |<br>
+ directory := aFileDirectory.<br>
+ directory ifNil: [^ self].<br>
+ <br>
+ normalizedDirectory := directory withNormalizedPath.<br>
+ normalizedDirectory pathName = directory pathName<br>
+ ifFalse: [directory := normalizedDirectory].<br>
+ self flag: #workaround. "Avoid reassigning the directory as long as possible because PluggableTreeMorph does not perform equality comparison when reselecting items. See comment in #setDirectoryTo:."</span><br>
<br>
<b>FileDirectory class>>forPathParts: {instance creation} · ct 7/9/2022 17:12</b><br>
<span style="color: #FF0000">+ forPathParts: pathParts<br>
+ <br>
+ | fileName |<br>
+ fileName := String streamContents: [:stream |<br>
+ pathParts do: [:part |<br>
+ stream<br>
+ nextPutAll: self slash;<br>
+ nextPutAll: part]].<br>
+ ^ self on: fileName</span><br>
<br>
<b>FileDirectory>>= {comparing} · ct 7/9/2022 17:24 (changed)</b><br>
= aDirectory<br>
"Compare two FileDirectory instances."<br>
<br>
^(aDirectory isKindOf: FileDirectory) and: [<br>
<span style="color: #FF0000">+ self flag: #todo. "ct: Should we normalize paths here?"<br>
</span> (pathName asString <br>
compare: aDirectory pathName asString <br>
caseSensitive: (self isCaseSensitive or: [ aDirectory isCaseSensitive ])) = 2 ]<br>
<br>
<b>FileDirectory>>withNormalizedPath {path access} · ct 7/9/2022 19:55</b><br>
<span style="color: #FF0000">+ withNormalizedPath<br>
+ "Answer a similar instance to the receiver with a normalized path, i.e., all path navigators such as . or .. will be eliminated."<br>
+ <br>
+ | normalizedParts originalParts |<br>
+ originalParts := self pathParts.<br>
+ normalizedParts := OrderedCollection new: originalParts size.<br>
+ originalParts do: [:part |<br>
+ part<br>
+ caseOf:<br>
+ {[self class parentDirectoryNickname] -><br>
+ [normalizedParts size > 0 ifTrue:<br>
+ [normalizedParts removeLast]].<br>
+ [self class currentDirectoryNickname] -> []}<br>
+ otherwise: [normalizedParts add: part]].<br>
+ ^ self class forPathParts: normalizedParts</span><br>
<br>
<b>UnixFileDirectoryTests>>testWithNormalizedPath {tests} · ct 7/9/2022 19:46</b><br>
<span style="color: #FF0000">+ testWithNormalizedPath<br>
+ <br>
+ FileDirectory activeDirectoryClass == UnixFileDirectory ifFalse:[^self].<br>
+ <br>
+ self assert: '/media/plonk/griffle' equals: (FileDirectory on: '/media/plonk/griffle') withNormalizedPath pathName.<br>
+ <br>
+ self assert: '/media/plonk/griffle' equals: (FileDirectory on: '/media/./plonk/././griffle/./') withNormalizedPath pathName.<br>
+ self assert: '/media/plonk/wiffy' equals: (FileDirectory on: '/media/../../media/plonk/../plonk/griffle/../wiffy/ziffy/..') withNormalizedPath pathName.</span><br>
<br>
["normalize-paths.2.cs"]<br>
<br>
<span style="color: #808080">---<br>
</span><span style="color: #808080"><i>Sent from </i></span><span style="color: #808080"><i><a href="https://github.com/hpi-swa-lab/squeak-inbox-talk"><u><span style="color: #808080">Squeak Inbox Talk</span></u></a></i></span><br>
["normalize-paths.2.cs"]
</div></blockquote></div>