ShellView.st
author Patrik Svestka <patrik.svestka@gmail.com>
Wed, 14 Nov 2018 12:07:51 +0100
branchjv
changeset 3630 5e718e0a754e
parent 874 ab93fcd829c5
permissions -rw-r--r--
Issue #239: Fix all Smalltak/X source files to be in unicode (UTF8 without BOM) and prefixed by "{ Encoding: utf8 }" when any unicode character is present

- All source *.st files are now Unicode UTF8 without BOM
Files are in two groups (fileOut works this way in Smalltalk/X):
- containing a unicode character have "{ Encoding: utf8 }" at the header
- ASCII only are without the header
     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 resource specification was automatically generated
    53      by the UIPainter of ST/X."
    54 
    55     "Do not manually edit this!! If it is corrupted,
    56      the UIPainter may not be able to read the specification."
    57 
    58     "
    59      UIPainter new openOnClass:ShellView andSelector:#windowSpec
    60      ShellView new openInterface:#windowSpec
    61      ShellView open
    62     "
    63 
    64     <resource: #canvas>
    65 
    66     ^
    67      
    68        #(#FullSpec
    69           #window: 
    70            #(#WindowSpec
    71               #name: 'unnamed canvas'
    72               #layout: #(#LayoutFrame 252 0 229 0 551 0 497 0)
    73               #label: 'unnamed canvas'
    74               #min: #(#Point 10 10)
    75               #max: #(#Point 1152 864)
    76               #bounds: #(#Rectangle 252 229 552 498)
    77               #usePreferredExtent: false
    78           )
    79           #component: 
    80            #(#SpecCollection
    81               #collection: 
    82                #(
    83                  #(#TextEditorSpec
    84                     #name: 'fileContentsView'
    85                     #layout: #(#LayoutFrame 0 0 0 0.0 0 1 -22 1)
    86                     #model: #valueOfFileContents
    87                     #hasHorizontalScrollBar: true
    88                     #hasVerticalScrollBar: true
    89                     #miniScrollerHorizontal: true
    90                 )
    91                  #(#SequenceViewSpec
    92                     #name: 'shellOutputView'
    93                     #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 -22 1.0)
    94                     #model: #selectionOfShellOutput
    95                     #style: #(#FontDescription #courier #medium #roman 12)
    96                     #hasHorizontalScrollBar: true
    97                     #hasVerticalScrollBar: 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     |dir|
   142     (directory ~= (dir := aDirectory asFilename asAbsoluteFilename name))
   143     ifTrue:
   144     [
   145         directory := dir.
   146         self listOfShellOutput
   147                 at: self listOfShellOutput size
   148                 put: self getDirectoryTextString
   149     ]
   150 !
   151 
   152 numberOfMaxLines
   153 
   154     ^numberOfMaxLines ? (numberOfMaxLines := 500)
   155 !
   156 
   157 numberOfMaxLines: anInteger
   158 
   159     numberOfMaxLines := anInteger
   160 ! !
   161 
   162 !ShellView methodsFor:'accessing - views'!
   163 
   164 commandInputField
   165 
   166     ^builder componentAt: #commandInputField
   167 !
   168 
   169 fileContentsView
   170 
   171     ^builder componentAt: #fileContentsView
   172 !
   173 
   174 fileNameButton
   175 
   176     ^builder componentAt: #fileNameButton
   177 !
   178 
   179 saveButton
   180 
   181     ^builder componentAt: #saveButton
   182 !
   183 
   184 shellOutputView
   185 
   186     ^builder componentAt: #shellOutputView
   187 !
   188 
   189 stopButton
   190 
   191     ^builder componentAt: #stopButton
   192 ! !
   193 
   194 !ShellView methodsFor:'actions'!
   195 
   196 executeCommand: aCommand
   197 
   198     |s|       
   199     aCommand isNil | task notNil | directory isNil ifTrue: [^nil].
   200     aCommand isString ifTrue: [^self executeCommands: (Array with: aCommand)].
   201     aCommand key size = 0 ifTrue: [^aCommand key: ''].
   202 
   203     self valueOfCommand value: ''.
   204     self listOfShellOutput
   205         at: self listOfShellOutput size
   206         put: self getDirectoryTextString, (Text string: aCommand key color: Color blue).
   207 
   208     aCommand key trimBlanks = 'clear'
   209     ifTrue: 
   210     [
   211         self shellOutputView raise.
   212         ^self listOfShellOutput contents: (Array with: self getDirectoryTextString).
   213     ].
   214 
   215     (((s := aCommand key readStream) nextWord = 'cd') and: [(s next = Character space) | s atEnd])
   216     ifTrue:
   217     [
   218         s := s upToEnd trimBlanks.
   219 
   220         s size = 0
   221         ifTrue:
   222         [
   223             s := Filename homeDirectory
   224         ]
   225         ifFalse: 
   226         [
   227             s first = $/
   228                 ifTrue: [s := s asFilename]
   229                 ifFalse: [s := self directory asFilename constructDirectory: s]
   230         ].
   231         (s exists and: [s isDirectory])
   232         ifTrue:
   233         [
   234             directory := s name.
   235             ^self listOfShellOutput contents: (Array with: self getDirectoryTextString).
   236         ].
   237     ].
   238 
   239     self stopButton raise.
   240     self shellOutputView raise.
   241 
   242     self
   243         execute: aCommand key
   244         exit:
   245         [
   246             self commandInputField raise.
   247             aCommand value: true. 
   248             self executeNextCommand.
   249             self append: self getDirectoryTextString
   250         ].
   251 ! !
   252 
   253 !ShellView methodsFor:'aspects'!
   254 
   255 listOfShellOutput
   256 
   257     |holder|
   258     (holder := builder bindingAt:#listOfShellOutput) isNil ifTrue:[
   259         builder aspectAt:#listOfShellOutput put:(holder :=  List new).
   260         holder add: self getDirectoryTextString
   261     ].  
   262     ^holder
   263 !
   264 
   265 selectionOfShellOutput
   266 
   267     |holder|              
   268     (holder := builder bindingAt:#selectionOfShellOutput) isNil ifTrue:[
   269         builder aspectAt:#selectionOfShellOutput put: (holder := 1 asValue)
   270     ]. 
   271     ^holder
   272 !
   273 
   274 valueOfCommand
   275 
   276     |holder|
   277     (holder := builder bindingAt:#valueOfCommand) isNil ifTrue:[
   278         builder aspectAt:#valueOfCommand put:
   279             (holder :=  AspectAdaptor new subject: self; forAspect: #currentCommand).
   280     ].
   281     ^ holder       
   282 !
   283 
   284 valueOfFileContents
   285 
   286     |holder|
   287     (holder := builder bindingAt:#valueOfFileContents) isNil ifTrue:[
   288         builder aspectAt:#valueOfFileContents put:(holder :=  ValueHolder new).
   289     ].
   290     ^holder    
   291 ! !
   292 
   293 !ShellView methodsFor:'callbacks'!
   294 
   295 listDoubleClicked: anLineIndex
   296 
   297     |stream streamAtLine possibleFileName selectedFileName fileFound|
   298     possibleFileName := ''.
   299     stream := (self listOfShellOutput at: anLineIndex) string readStream.
   300     fileFound := false.
   301     [stream atEnd | fileFound]
   302     whileFalse: 
   303     [                
   304         possibleFileName := possibleFileName, stream next.
   305         (("((selectedFileName := possibleFileName) asFilename exists) or:"
   306         (selectedFileName := directory, Filename separator, possibleFileName) asFilename exists)
   307          and: [selectedFileName asFilename isDirectory not])
   308         ifTrue:
   309         [   
   310             |possibleLineIndex listSize lineNumber|   
   311             fileFound := true.  
   312             self openFile: selectedFileName.
   313             [stream atEnd | lineNumber notNil]
   314             whileFalse: 
   315             [            
   316                 lineNumber := Integer readFrom: stream nextAlphaNumericWord onError: nil.
   317             ].
   318             lineNumber := lineNumber ? 1.
   319             listSize := self fileContentsView list size.
   320             (lineNumber between: 1 and: listSize)
   321             ifTrue:
   322             [          
   323                 self fileContentsView selectLine: lineNumber
   324             ].
   325             lineNumber > listSize
   326             ifTrue:
   327             [          
   328                 self fileContentsView selectLine: listSize
   329             ].
   330         ].
   331     ]
   332 
   333 ! !
   334 
   335 !ShellView methodsFor:'initialization'!
   336 
   337 initialize
   338     super initialize.
   339     self createBuilder
   340 
   341     "Created: / 20.6.1998 / 15:30:48 / cg"
   342 ! !
   343 
   344 !ShellView methodsFor:'private'!
   345 
   346 append:anElement
   347 
   348     anElement notNil
   349     ifTrue:
   350     [   
   351         self listOfShellOutput size > self numberOfMaxLines
   352         ifTrue:
   353         [
   354             self listOfShellOutput contents: (self listOfShellOutput copyFrom:
   355                 self listOfShellOutput size - (self numberOfMaxLines//5)
   356                 to: self listOfShellOutput size)
   357         ].
   358         self listOfShellOutput add: anElement.
   359         self selectionOfShellOutput value: self listOfShellOutput size.
   360     ]
   361            
   362 !
   363 
   364 execute: cmd exit:exitAction
   365 
   366     |outStream|
   367     self terminateTask.
   368     outStream:= PipeStream readingFrom: cmd errorDisposition:#inline inDirectory: directory.
   369     task :=
   370     [          
   371         [      
   372             outStream canReadWithoutBlocking
   373             ifTrue:
   374             [
   375                 outStream readWait.
   376                 self append: (outStream upTo: Character cr).
   377             ].
   378         ] doWhile:[outStream atEnd not]
   379     ] forkAt: Processor userBackgroundPriority.
   380 
   381     task addExitAction:
   382     [
   383         task := nil.
   384         outStream shutDown.
   385         exitAction value
   386     ]
   387 !
   388 
   389 executeNextCommand
   390 
   391     self executeCommand: (commands detect: [:str| str value = false] ifNone: nil)
   392 
   393 !
   394 
   395 getDirectoryTextString
   396 
   397     ^Text string: ('[',self directory, '] > ') emphasis: #bold
   398 !
   399 
   400 listDirectory: dir
   401 
   402     |s match d|   
   403     match := (dir name copy reverse upTo: Filename separator) reverse.
   404 
   405     s := dir name copy reverse readStream.
   406     s through: Filename separator.
   407     s := s upToEnd reverse.
   408     dir name = Filename separator asString ifTrue: [s := Filename separator asString].
   409 
   410     ((d := dir) isDirectory or:
   411     [((d := s asFilename) isDirectory or:
   412     [(d := directory asFilename construct: s) isDirectory])])
   413 
   414      ifTrue: [        
   415     d directoryContents do:
   416     [:dirEntry|      
   417         ((match, '*') match: dirEntry) ifTrue: [self append:dirEntry]
   418     ].
   419     self append: self getDirectoryTextString
   420     ]
   421 ! !
   422 
   423 !ShellView methodsFor:'selection'!
   424 
   425 currentCommand
   426 
   427     ^currentCommand
   428 !
   429 
   430 currentCommand: aString
   431 
   432     self commandInputField crAction: [self executeCommands: (Array with: currentCommand)].
   433     self commandInputField entryCompletionBlock:[:contents |
   434         |newString|
   435         newString := Filename 
   436                         filenameCompletionFor:contents 
   437                         directory:directory asFilename
   438                         directoriesOnly:false 
   439                         filesOnly:false 
   440                         ifMultiple:
   441                             [:dir |
   442                                 self listDirectory: dir.
   443                                 self commandInputField flash.
   444                             ].            
   445         self commandInputField contents:newString.
   446         self commandInputField cursorToEndOfLine.
   447     ].
   448     currentCommand := aString.
   449     self listOfShellOutput size > 0
   450     ifTrue:
   451     [
   452         self listOfShellOutput
   453             at: self listOfShellOutput size
   454             put: self getDirectoryTextString, currentCommand
   455     ].
   456 
   457 ! !
   458 
   459 !ShellView methodsFor:'user actions'!
   460 
   461 executeCommands: aStingCollection
   462 
   463     commands := aStingCollection collect: [:str| str->false].
   464 
   465     self executeNextCommand
   466 !
   467 
   468 openFile: aFileName
   469 
   470     |fileName|
   471     task isNil & (((fileName := aFileName asFilename) exists)
   472     or: [(fileName := directory asFilename construct: fileName) exists])
   473     ifTrue:
   474     [        
   475         self fileNameButton raise; sizeFixed: true;label: fileName name.
   476         self fileContentsView raise.
   477         self saveButton raise.
   478         Stream readErrorSignal
   479         handle:
   480         [:ex|
   481             self warn: 'Reading file contents failed!!'.
   482             self toggleViews.
   483         ]
   484         do:
   485         [
   486             self valueOfFileContents value: fileName contentsOfEntireFile
   487         ]
   488     ]  
   489 !
   490 
   491 saveFileContents
   492 
   493     self fileContentsView saveAs: self fileNameButton label
   494 !
   495 
   496 terminateTask
   497 
   498     task notNil ifTrue:
   499     [ 
   500         task terminate.
   501         task := nil
   502     ]   
   503 !
   504 
   505 toggleViews
   506 
   507     self fileNameButton label isEmpty
   508     ifFalse:
   509     [
   510         task notNil
   511             ifTrue: [self stopButton raise]
   512             ifFalse: [self commandInputField raise].
   513         self shellOutputView raise.
   514         self fileNameButton sizeFixed: true; label: ''.
   515         self valueOfFileContents value: ''.
   516     ]
   517     ifTrue:
   518     [         
   519         self fileNameButton raise.
   520         self infoLabel raise.
   521         self fileContentsView raise
   522     ]
   523 ! !
   524 
   525 !ShellView class methodsFor:'documentation'!
   526 
   527 version
   528     ^ '$Header$'
   529 ! !