ShellView.st
changeset 643 d6e1a9fced34
child 757 d28fb65967a9
equal deleted inserted replaced
642:f8ba35e5a678 643:d6e1a9fced34
       
     1 "
       
     2  COPYRIGHT (c) 1997 by eXept Software AG
       
     3               All Rights Reserved
       
     4 
       
     5  This software is furnished under a license and may be used
       
     6  only in accordance with the terms of that license and with the
       
     7  inclusion of the above copyright notice. This software may not
       
     8  be provided or otherwise made available to, or used by, any
       
     9  other person. No title to or ownership of the software is
       
    10  hereby transferred.
       
    11 "
       
    12 
       
    13 
       
    14 
       
    15 ApplicationModel subclass:#ShellView
       
    16 	instanceVariableNames:'task directory commands currentCommand numberOfMaxLines'
       
    17 	classVariableNames:''
       
    18 	poolDictionaries:''
       
    19 	category:'Interface-Support'
       
    20 !
       
    21 
       
    22 !ShellView class methodsFor:'documentation'!
       
    23 
       
    24 copyright
       
    25 "
       
    26  COPYRIGHT (c) 1997 by eXept Software AG
       
    27               All Rights Reserved
       
    28 
       
    29  This software is furnished under a license and may be used
       
    30  only in accordance with the terms of that license and with the
       
    31  inclusion of the above copyright notice. This software may not
       
    32  be provided or otherwise made available to, or used by, any
       
    33  other person. No title to or ownership of the software is
       
    34  hereby transferred.
       
    35 "
       
    36 
       
    37 
       
    38 !
       
    39 
       
    40 documentation
       
    41 "
       
    42     [author:]
       
    43         Thomas Zwick
       
    44 "
       
    45 
       
    46 
       
    47 ! !
       
    48 
       
    49 !ShellView class methodsFor:'interface specs'!
       
    50 
       
    51 windowSpec
       
    52     "this window spec was automatically generated by the ST/X UIPainter"
       
    53 
       
    54     "do not manually edit this - the painter/builder may not be able to
       
    55      handle the specification if its corrupted."
       
    56 
       
    57     "
       
    58      UIPainter new openOnClass:ShellView andSelector:#windowSpec
       
    59      ShellView new openInterface:#windowSpec
       
    60     "
       
    61     "ShellView open"
       
    62 
       
    63     <resource: #canvas>
       
    64 
       
    65     ^
       
    66      
       
    67        #(#FullSpec
       
    68           #'window:' 
       
    69            #(#WindowSpec
       
    70               #'name:' 'unnamed canvas'
       
    71               #'layout:' #(#LayoutFrame 197 0 172 0 496 0 440 0)
       
    72               #'label:' 'unnamed canvas'
       
    73               #'min:' #(#Point 10 10)
       
    74               #'max:' #(#Point 1152 864)
       
    75               #'bounds:' #(#Rectangle 197 172 497 441)
       
    76               #'usePreferredExtent:' false
       
    77           )
       
    78           #'component:' 
       
    79            #(#SpecCollection
       
    80               #'collection:' 
       
    81                #(
       
    82                  #(#TextEditorSpec
       
    83                     #'name:' 'fileContentsView'
       
    84                     #'layout:' #(#LayoutFrame 0 0 0 0.0 0 1 -22 1)
       
    85                     #'model:' #valueOfFileContents
       
    86                     #'hasHorizontalScrollBar:' true
       
    87                     #'hasVerticalScrollBar:' true
       
    88                     #'miniScrollerHorizontal:' true
       
    89                 )
       
    90                  #(#SequenceViewSpec
       
    91                     #'name:' 'shellOutputView'
       
    92                     #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 -22 1.0)
       
    93                     #'model:' #selectionOfShellOutput
       
    94                     #'style:' #(#FontDescription #courier #medium #roman 12)
       
    95                     #'hasHorizontalScrollBar:' true
       
    96                     #'hasVerticalScrollBar:' true
       
    97                     #'miniScrollerHorizontal:' true
       
    98                     #'doubleClickSelector:' #'listDoubleClicked:'
       
    99                     #'useIndex:' true
       
   100                     #'sequenceList:' #listOfShellOutput
       
   101                 )
       
   102                  #(#ActionButtonSpec
       
   103                     #'name:' 'fileNameButton'
       
   104                     #'layout:' #(#LayoutFrame 0 0.0 -22 1 -60 1.0 0 1.0)
       
   105                     #'model:' #toggleViews
       
   106                 )
       
   107                  #(#ActionButtonSpec
       
   108                     #'name:' 'saveButton'
       
   109                     #'layout:' #(#LayoutFrame -60 1 -22 1 0 1.0 0 1.0)
       
   110                     #'label:' 'Save'
       
   111                     #'model:' #saveFileContents
       
   112                 )
       
   113                  #(#ActionButtonSpec
       
   114                     #'name:' 'stopButton'
       
   115                     #'layout:' #(#LayoutFrame 0 0 -22 1 0 1.0 0 1)
       
   116                     #'label:' 'Stop'
       
   117                     #'model:' #terminateTask
       
   118                 )
       
   119                  #(#InputFieldSpec
       
   120                     #'name:' 'commandInputField'
       
   121                     #'layout:' #(#LayoutFrame 0 0 -22 1 0 1.0 0 1)
       
   122                     #'model:' #valueOfCommand
       
   123                     #'type:' #string
       
   124                     #'acceptOnReturn:' false
       
   125                     #'acceptOnTab:' false
       
   126                 )
       
   127               )
       
   128           )
       
   129       )
       
   130 ! !
       
   131 
       
   132 !ShellView methodsFor:'accessing'!
       
   133 
       
   134 directory
       
   135 
       
   136     ^directory ? (directory := Filename currentDirectory asAbsoluteFilename name) 
       
   137 !
       
   138 
       
   139 directory: aDirectory
       
   140 
       
   141     directory := aDirectory asFilename asAbsoluteFilename name
       
   142 !
       
   143 
       
   144 numberOfMaxLines
       
   145 
       
   146     ^numberOfMaxLines ? (numberOfMaxLines := 500)
       
   147 !
       
   148 
       
   149 numberOfMaxLines: anInteger
       
   150 
       
   151     numberOfMaxLines := anInteger
       
   152 ! !
       
   153 
       
   154 !ShellView methodsFor:'accessing - views'!
       
   155 
       
   156 commandInputField
       
   157 
       
   158     ^builder componentAt: #commandInputField
       
   159 !
       
   160 
       
   161 fileContentsView
       
   162 
       
   163     ^builder componentAt: #fileContentsView
       
   164 !
       
   165 
       
   166 fileNameButton
       
   167 
       
   168     ^builder componentAt: #fileNameButton
       
   169 !
       
   170 
       
   171 saveButton
       
   172 
       
   173     ^builder componentAt: #saveButton
       
   174 !
       
   175 
       
   176 shellOutputView
       
   177 
       
   178     ^builder componentAt: #shellOutputView
       
   179 !
       
   180 
       
   181 stopButton
       
   182 
       
   183     ^builder componentAt: #stopButton
       
   184 ! !
       
   185 
       
   186 !ShellView methodsFor:'actions'!
       
   187 
       
   188 executeCommand: aCommand
       
   189 
       
   190     |s|       
       
   191     aCommand isNil | task notNil | directory isNil ifTrue: [^nil].
       
   192     aCommand key size = 0 ifTrue: [^aCommand key: ''].
       
   193 
       
   194     self valueOfCommand value: ''.
       
   195     self listOfShellOutput
       
   196         at: self listOfShellOutput size
       
   197         put: self getDirectoryTextString, (Text string: aCommand key color: Color blue).
       
   198 
       
   199     aCommand key trimBlanks = 'clear'
       
   200     ifTrue: 
       
   201     [
       
   202         self shellOutputView raise.
       
   203         ^self listOfShellOutput contents: (Array with: self getDirectoryTextString).
       
   204     ].
       
   205 
       
   206     (((s := aCommand key readStream) nextWord = 'cd') and: [(s next = Character space) | s atEnd])
       
   207     ifTrue:
       
   208     [
       
   209         s := s upToEnd trimBlanks.
       
   210 
       
   211         s size = 0
       
   212         ifTrue:
       
   213         [
       
   214             s := Filename homeDirectory
       
   215         ]
       
   216         ifFalse: 
       
   217         [
       
   218             s first = $/
       
   219                 ifTrue: [s := s asFilename]
       
   220                 ifFalse: [s := self directory asFilename constructDirectory: s]
       
   221         ].
       
   222         (s exists and: [s isDirectory])
       
   223         ifTrue:
       
   224         [
       
   225             directory := s name.
       
   226             ^self listOfShellOutput contents: (Array with: self getDirectoryTextString).
       
   227         ].
       
   228     ].
       
   229 
       
   230     self stopButton raise.
       
   231     self shellOutputView raise.
       
   232 
       
   233     self
       
   234         execute: aCommand key
       
   235         exit:
       
   236         [
       
   237             self commandInputField raise.
       
   238             aCommand value: true. 
       
   239             self executeNextCommand.
       
   240             self append: self getDirectoryTextString
       
   241         ].
       
   242 ! !
       
   243 
       
   244 !ShellView methodsFor:'aspects'!
       
   245 
       
   246 listOfShellOutput
       
   247 
       
   248     |holder|
       
   249     (holder := builder bindingAt:#listOfShellOutput) isNil ifTrue:[
       
   250         builder aspectAt:#listOfShellOutput put:(holder :=  List new).
       
   251         holder add: self getDirectoryTextString
       
   252     ].  
       
   253     ^holder
       
   254 !
       
   255 
       
   256 selectionOfShellOutput
       
   257 
       
   258     |holder|              
       
   259     (holder := builder bindingAt:#selectionOfShellOutput) isNil ifTrue:[
       
   260         builder aspectAt:#selectionOfShellOutput put: (holder := 1 asValue)
       
   261     ]. 
       
   262     ^holder
       
   263 !
       
   264 
       
   265 valueOfCommand
       
   266 
       
   267     |holder|
       
   268     (holder := builder bindingAt:#valueOfCommand) isNil ifTrue:[
       
   269         builder aspectAt:#valueOfCommand put:
       
   270             (holder :=  AspectAdaptor new subject: self; forAspect: #currentCommand).
       
   271     ].
       
   272     ^ holder       
       
   273 !
       
   274 
       
   275 valueOfFileContents
       
   276 
       
   277     |holder|
       
   278     (holder := builder bindingAt:#valueOfFileContents) isNil ifTrue:[
       
   279         builder aspectAt:#valueOfFileContents put:(holder :=  ValueHolder new).
       
   280     ].
       
   281     ^holder    
       
   282 ! !
       
   283 
       
   284 !ShellView methodsFor:'callbacks'!
       
   285 
       
   286 listDoubleClicked: anLineIndex
       
   287 
       
   288     |stream streamAtLine possibleFileName selectedFileName fileFound|
       
   289     possibleFileName := ''.
       
   290     stream := (self listOfShellOutput at: anLineIndex) readStream.
       
   291     fileFound := false.
       
   292     [stream atEnd | fileFound]
       
   293     whileFalse: 
       
   294     [
       
   295         possibleFileName := possibleFileName, stream next.
       
   296         ((((selectedFileName := possibleFileName) asFilename exists) or:
       
   297         [(selectedFileName := directory, Filename separator, possibleFileName) asFilename exists])
       
   298          and: [selectedFileName asFilename isDirectory not])
       
   299         ifTrue:
       
   300         [   
       
   301             |possibleLineIndex listSize lineNumber|
       
   302             fileFound := true.  
       
   303             self openFile: selectedFileName.
       
   304             [stream atEnd | lineNumber notNil]
       
   305             whileFalse: 
       
   306             [
       
   307                 lineNumber := Integer readFrom: stream nextAlphaNumericWord onError: nil.
       
   308             ].
       
   309             lineNumber := lineNumber ? 1.
       
   310             listSize := self fileContentsView list size.
       
   311             (lineNumber between: 1 and: listSize)
       
   312             ifTrue:
       
   313             [          
       
   314                 self fileContentsView selectLine: lineNumber
       
   315             ].
       
   316             lineNumber > listSize
       
   317             ifTrue:
       
   318             [          
       
   319                 self fileContentsView selectLine: listSize
       
   320             ].
       
   321         ].
       
   322     ]
       
   323 
       
   324 ! !
       
   325 
       
   326 !ShellView methodsFor:'private'!
       
   327 
       
   328 append:anElement
       
   329 
       
   330     anElement notNil
       
   331     ifTrue:
       
   332     [   
       
   333         self listOfShellOutput size > self numberOfMaxLines
       
   334         ifTrue:
       
   335         [
       
   336             self listOfShellOutput contents: (self listOfShellOutput copyFrom:
       
   337                 self listOfShellOutput size - (self numberOfMaxLines//5)
       
   338                 to: self listOfShellOutput size)
       
   339         ].
       
   340         self listOfShellOutput add: anElement.
       
   341         self selectionOfShellOutput value: self listOfShellOutput size.
       
   342     ]
       
   343            
       
   344 !
       
   345 
       
   346 execute: cmd exit:exitAction
       
   347 
       
   348     |outStream|
       
   349     self terminateTask.
       
   350     outStream:= PipeStream readingFrom: cmd errorDisposition:#inline inDirectory: directory.
       
   351     task :=
       
   352     [          
       
   353         [      
       
   354             outStream canReadWithoutBlocking
       
   355             ifTrue:
       
   356             [
       
   357                 outStream readWait.
       
   358                 self append: (outStream upTo: Character cr).
       
   359             ].
       
   360         ] doWhile:[outStream atEnd not]
       
   361     ] forkAt: Processor userBackgroundPriority.
       
   362 
       
   363     task addExitAction:
       
   364     [
       
   365         task := nil.
       
   366         outStream shutDown.
       
   367         exitAction value
       
   368     ]
       
   369 !
       
   370 
       
   371 executeNextCommand
       
   372 
       
   373     self executeCommand: (commands detect: [:str| str value = false] ifNone: nil)
       
   374 
       
   375 !
       
   376 
       
   377 getDirectoryTextString
       
   378 
       
   379     ^Text string: ('[',self directory, '] > ') emphasis: #bold
       
   380 !
       
   381 
       
   382 listDirectory: dir
       
   383 
       
   384     |s match d|   
       
   385     match := (dir name copy reverse upTo: Filename separator) reverse.
       
   386 
       
   387     s := dir name copy reverse readStream.
       
   388     s through: Filename separator.
       
   389     s := s upToEnd reverse.
       
   390     dir name = Filename separator asString ifTrue: [s := Filename separator asString].
       
   391 
       
   392     ((d := dir) isDirectory or:
       
   393     [((d := s asFilename) isDirectory or:
       
   394     [(d := directory asFilename construct: s) isDirectory])])
       
   395 
       
   396      ifTrue: [        
       
   397     d directoryContents do:
       
   398     [:dirEntry|      
       
   399         ((match, '*') match: dirEntry) ifTrue: [self append:dirEntry]
       
   400     ].
       
   401     self append: self getDirectoryTextString
       
   402     ]
       
   403 ! !
       
   404 
       
   405 !ShellView methodsFor:'selection'!
       
   406 
       
   407 currentCommand
       
   408 
       
   409     ^currentCommand
       
   410 !
       
   411 
       
   412 currentCommand: aString
       
   413 
       
   414     self commandInputField crAction: [self executeCommands: (Array with: currentCommand)].
       
   415     self commandInputField entryCompletionBlock:[:contents |
       
   416         |newString|
       
   417         newString := Filename 
       
   418                         filenameCompletionFor:contents 
       
   419                         directory:directory asFilename
       
   420                         directoriesOnly:false 
       
   421                         filesOnly:false 
       
   422                         ifMultiple:
       
   423                             [:dir |
       
   424                                 self listDirectory: dir.
       
   425                                 self commandInputField flash.
       
   426                             ].            
       
   427         self commandInputField contents:newString.
       
   428         self commandInputField cursorToEndOfLine.
       
   429     ].
       
   430     currentCommand := aString.
       
   431     self listOfShellOutput size > 0
       
   432     ifTrue:
       
   433     [
       
   434         self listOfShellOutput
       
   435             at: self listOfShellOutput size
       
   436             put: self getDirectoryTextString, currentCommand
       
   437     ].
       
   438 
       
   439 ! !
       
   440 
       
   441 !ShellView methodsFor:'user actions'!
       
   442 
       
   443 executeCommands: aStingCollection
       
   444 
       
   445     commands := aStingCollection collect: [:str| str->false].
       
   446 
       
   447     self executeNextCommand
       
   448 !
       
   449 
       
   450 openFile: aFileName
       
   451 
       
   452     |fileName|
       
   453     task isNil & (((fileName := aFileName asFilename) exists)
       
   454     or: [(fileName := directory asFilename construct: fileName) exists])
       
   455     ifTrue:
       
   456     [        
       
   457         self fileNameButton raise; sizeFixed: true;label: fileName name.
       
   458         self fileContentsView raise.
       
   459         self saveButton raise.
       
   460         Stream readErrorSignal
       
   461         handle:
       
   462         [:ex|
       
   463             self warn: 'Reading file contents failed!!'.
       
   464             self toggleViews.
       
   465         ]
       
   466         do:
       
   467         [
       
   468             self valueOfFileContents value: fileName contentsOfEntireFile
       
   469         ]
       
   470     ]  
       
   471 !
       
   472 
       
   473 saveFileContents
       
   474 
       
   475     self fileContentsView saveAs: self fileNameButton label
       
   476 !
       
   477 
       
   478 terminateTask
       
   479 
       
   480     task notNil ifTrue:
       
   481     [ 
       
   482         task terminate.
       
   483         task := nil
       
   484     ]   
       
   485 !
       
   486 
       
   487 toggleViews
       
   488 
       
   489     self fileNameButton label isEmpty
       
   490     ifFalse:
       
   491     [
       
   492         task notNil
       
   493             ifTrue: [self stopButton raise]
       
   494             ifFalse: [self commandInputField raise].
       
   495         self shellOutputView raise.
       
   496         self fileNameButton sizeFixed: true; label: ''.
       
   497         self valueOfFileContents value: ''.
       
   498     ]
       
   499     ifTrue:
       
   500     [         
       
   501         self fileNameButton raise.
       
   502         self infoLabel raise.
       
   503         self fileContentsView raise
       
   504     ]
       
   505 ! !
       
   506 
       
   507 !ShellView class methodsFor:'documentation'!
       
   508 
       
   509 version
       
   510     ^ '$Header$'
       
   511 ! !