diff -r 01a0c0902b67 -r 017c88672c98 Filename.st --- a/Filename.st Tue Sep 19 02:55:04 1995 +0200 +++ b/Filename.st Thu Sep 21 14:31:48 1995 +0200 @@ -20,7 +20,7 @@ COPYRIGHT (c) 1992 by Claus Gittinger All Rights Reserved -$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.32 1995-09-07 11:58:28 claus Exp $ +$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.33 1995-09-21 12:30:32 claus Exp $ '! !Filename class methodsFor:'documentation'! @@ -41,7 +41,7 @@ version " -$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.32 1995-09-07 11:58:28 claus Exp $ +$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.33 1995-09-21 12:30:32 claus Exp $ " ! @@ -352,6 +352,94 @@ ^ #('/') "Modified: 7.9.1995 / 10:45:25 / claus" +! + +filenameCompletionFor:aString directory:inDirectory directoriesOnly:directoriesOnly filesOnly:filesOnly ifMultiple:aBlock + "perform filename completion on aString in some directory; + return the longest matching filename prefix as a string. + If directoriesOnly and filesOnly are true, only directories and files + are considered respectively. If multiple files match, the exception + block aBlock is evaluated with a filename representing the directory + (where the match was done) as argument. + (this may be different from the inDirectory argument, if aString is absolute + or starts with ../)" + + |s f matchSet nMatch name words dir| + + s := aString. + " + find the last word ... + " + words := s asCollectionOfWords. + words size == 0 ifTrue:[ + ^ aBlock value:'.' asFilename + ]. + + f := words last asFilename. + + matchSet := f filenameCompletionIn:inDirectory. + + dir := f directory. + + directoriesOnly ifTrue:[ + matchSet := matchSet select:[:aFilename | + (dir construct:aFilename) isDirectory + ]. + ] ifFalse:[ + filesOnly ifTrue:[ + matchSet := matchSet select:[:aFilename | + (dir construct:aFilename) isDirectory not + ]. + ] + ]. + + (nMatch := matchSet size) ~~ 1 ifTrue:[ + " + more than one possible completion - + " + aBlock value:f + ]. + " + even with more than one possible completion, + f's name is now the common prefix + " + name := f asString. + nMatch == 1 ifTrue:[ + " + exactly one possible completion - + " + f := dir construct:matchSet first. + + directoriesOnly ifFalse:[ + f isDirectory ifTrue:[ + (name endsWith:(Filename separator)) ifFalse:[ + name := name , '/' + ]. + ]. + ] + ]. + + " + construct new contents, by taking + last words completion + " + s := ''. + 1 to:(words size - 1) do:[:idx | + s := s , (words at:idx) , ' ' + ]. + s := s , name. + + "/ special: if there was no change, and the string represented + "/ is a directories name, add a directory separator + s = aString ifTrue:[ + (s endsWith:Filename separator) ifFalse:[ + s asFilename isDirectory ifTrue:[ + ^ s , Filename separator asString + ] + ] + ]. + + ^ s ! ! !Filename methodsFor:'instance creation'! @@ -817,114 +905,139 @@ ! filenameCompletion - "try to complete the filename. This method has both a side effect, - and a return value: - it returns a collection of matching filename strings, - and sets (as side effect) the receivers filename to the longest common - match. - (i.e. if the size of the returned collection is exactly 1, - the completion has succeeded and the receivers name has been changed to - that. - If the returned collection is empty, nothing matched and the receivers - names is unchanged. - If the size of the returned collection is greater than one, the receivers - filename-string has been set to the longest common filename-prefix)" + "try to complete the recevier filename. + This method has both a return value and a side effect on the receiver: + it returns a collection of matching filename objects, + and leaves changes the receivers filename-string to the longest common + match. + If none matches, the returned collection is empty and the recevier is unchanged. + If there is only one match, the size of the returned collection is exactly 1, + containing the fully expanded filename and the receivers name is changed to it." - |dir name matching matchLen try allMatching sep parent prefix| + ^ self filenameCompletionIn:nil - sep := self class separator asString. - parent := self class parentDirectoryName. + " + 'mak' asFilename filenameCompletion + 'Make' asFilename filenameCompletion + 'Makef' asFilename filenameCompletion;yourself + '/u' asFilename filenameCompletion + '../../libpr' asFilename inspect filenameCompletion + " +! - dir := self directory. - prefix := parent , sep. - (nameString endsWith:sep) ifTrue:[ - name := '' - ] ifFalse:[ - name := self baseName. - ]. - [name startsWith:prefix] whileTrue:[ - self halt. - dir := dir directory. - name := name copyFrom:(prefix size + 1) +filenameCompletionIn:aDirectory + "try to complete the recevier filename. + This method has both a return value and a side effect on the receiver: + it returns a collection of matching filename objects, + and leaves changes the receivers filename-string to the longest common + match. + If none matches, the returned collection is empty and the recevier is unchanged. + If there is only one match, the size of the returned collection is exactly 1, + containing the fully expanded filename and the receivers name is changed to it." + + |dir baseName matching matchLen try allMatching + sepString parentString prefix nMatch| + + sepString := self class separator asString. + (nameString endsWith:sepString) ifTrue:[ + ^ #() ]. - dir := dir asString. - name = parent ifTrue:[ - ^ dir asFilename filenameCompletion + parentString := self class parentDirectoryName. + baseName := self baseName. + baseName ~= nameString ifTrue:[ + prefix := self directoryName. + ]. + + aDirectory isNil ifTrue:[ + dir := self directory + ] ifFalse:[ + dir := (aDirectory construct:nameString) directory ]. matching := OrderedCollection new. - (FileDirectory directoryNamed:dir) do:[:fileName | - ((fileName ~= '.') and:[fileName ~= parent]) ifTrue:[ - (fileName startsWith:name) ifTrue:[ + dir directoryContents do:[:fileName | + ((fileName ~= '.') and:[fileName ~= parentString]) ifTrue:[ + (fileName startsWith:baseName) ifTrue:[ matching add:fileName ] ] ]. - " - if there is only one, change my name ... + (nMatch := matching size) > 1 ifTrue:[ + " + find the longest common prefix + " + matchLen := baseName size. + matchLen > matching first size ifTrue:[ + try := baseName. + allMatching := false + ] ifFalse:[ + try := matching first copyTo:matchLen. + allMatching := true. + ]. + + [allMatching] whileTrue:[ + matching do:[:aName | + (aName startsWith:try) ifFalse:[ + allMatching := false + ] + ]. + allMatching ifTrue:[ + matchLen < matching first size ifTrue:[ + matchLen := matchLen + 1. + try := matching first copyTo:matchLen. + ] ifFalse:[ + allMatching := false + ] + ] ifFalse:[ + try := matching first copyTo:matchLen - 1. + ] + ]. + " + and set my name to the last full match + " + nameString := try + ]. + " - matching size == 1 ifTrue:[ - dir = sep ifTrue:[ - dir := '' + if I had a directory-prefix, change names in collection ... + " + prefix notNil ifTrue:[ + prefix = '/' ifTrue:[ + "/ avoid introducing double slashes + prefix := '' ]. - nameString := dir , sep , matching first. - matching first = name ifTrue:[ - self isDirectory ifTrue:[ - nameString := nameString , self class separator asString + matching := matching collect:[:n | prefix , '/' , n]. + nMatch == 1 ifTrue:[ + nameString := matching first + ] ifFalse:[ + nMatch > 1 ifTrue:[ + nameString := prefix , '/' , nameString ] ] ] ifFalse:[ - matching size > 1 ifTrue:[ - " - find the longest common prefix - " - matchLen := name size. - matchLen > matching first size ifTrue:[ - try := name. - allMatching := false - ] ifFalse:[ - try := matching first copyTo:matchLen. - allMatching := true. - ]. - - [allMatching] whileTrue:[ - matching do:[:aName | - (aName startsWith:try) ifFalse:[ - allMatching := false - ] - ]. - allMatching ifTrue:[ - matchLen < matching first size ifTrue:[ - matchLen := matchLen + 1. - try := matching first copyTo:matchLen. - ] ifFalse:[ - allMatching := false - ] - ] ifFalse:[ - try := matching first copyTo:matchLen - 1. - ] - ]. - " - and set my name to the last full match - " - dir = sep ifTrue:[ - dir := '' - ]. - nameString := dir , sep , try + nMatch == 1 ifTrue:[ + nameString := matching first ] ]. + " return the match-set, so caller can decide what to do (i.e. show the matches, output a warning etc ...) " ^ matching - " - 'Make' asFilename filenameCompletion;yourself - 'Makef' asFilename filenameCompletion;yourself - '/u' asFilename filenameCompletion - '../../libpr' asFilename filenameCompletion + " trivial cases: + + '../' asFilename filenameCompletion + '/' asFilename filenameCompletion + '/usr/' asFilename filenameCompletion + + 'mak' asFilename filenameCompletion + 'Make' asFilename filenameCompletion + 'Makef' asFilename filenameCompletion + '/u' asFilename filenameCompletion + '../../libpr' asFilename filenameCompletion " ! !