--- 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
"
! !