Platform-Services.st 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. Smalltalk createPackage: 'Platform-Services'!
  2. Object subclass: #ConsoleErrorHandler
  3. instanceVariableNames: ''
  4. package: 'Platform-Services'!
  5. !ConsoleErrorHandler commentStamp!
  6. I am manage Smalltalk errors, displaying the stack in the console.!
  7. !ConsoleErrorHandler methodsFor: 'error handling'!
  8. handleError: anError
  9. anError context ifNotNil: [ self logErrorContext: anError context ].
  10. self logError: anError
  11. ! !
  12. !ConsoleErrorHandler methodsFor: 'private'!
  13. log: aString
  14. console log: aString
  15. !
  16. logContext: aContext
  17. aContext home ifNotNil: [
  18. self logContext: aContext home ].
  19. self log: aContext asString
  20. !
  21. logError: anError
  22. self log: anError messageText
  23. !
  24. logErrorContext: aContext
  25. aContext ifNotNil: [
  26. aContext home ifNotNil: [
  27. self logContext: aContext home ]]
  28. ! !
  29. ConsoleErrorHandler class instanceVariableNames: 'current'!
  30. !ConsoleErrorHandler class methodsFor: 'initialization'!
  31. initialize
  32. ErrorHandler registerIfNone: self new
  33. ! !
  34. Object subclass: #ConsoleTranscript
  35. instanceVariableNames: 'textarea'
  36. package: 'Platform-Services'!
  37. !ConsoleTranscript commentStamp!
  38. I am a specific transcript emitting to the JavaScript console.
  39. If no other transcript is registered, I am the default.!
  40. !ConsoleTranscript methodsFor: 'actions'!
  41. open
  42. ! !
  43. !ConsoleTranscript methodsFor: 'printing'!
  44. clear
  45. "no op"
  46. !
  47. cr
  48. "no op"
  49. !
  50. show: anObject
  51. "Smalltalk objects should have no trouble displaying themselves on the Transcript; Javascript objects don't know how, so must be wrapped in a JSObectProxy."
  52. <console.log(String($recv(anObject)._asString()))>
  53. ! !
  54. !ConsoleTranscript class methodsFor: 'initialization'!
  55. initialize
  56. Transcript registerIfNone: self new
  57. ! !
  58. Object subclass: #InterfacingObject
  59. instanceVariableNames: ''
  60. package: 'Platform-Services'!
  61. !InterfacingObject commentStamp!
  62. I am superclass of all object that interface with user or environment. `Widget` and a few other classes are subclasses of me. I delegate all of the above APIs to `PlatformInterface`.
  63. ## API
  64. self alert: 'Hey, there is a problem'.
  65. self confirm: 'Affirmative?'.
  66. self prompt: 'Your name:'.
  67. self ajax: #{
  68. 'url' -> '/patch.js'. 'type' -> 'GET'. dataType->'script'
  69. }.!
  70. !InterfacingObject methodsFor: 'actions'!
  71. ajax: anObject
  72. ^ PlatformInterface ajax: anObject
  73. !
  74. alert: aString
  75. ^ PlatformInterface alert: aString
  76. !
  77. confirm: aString
  78. ^ PlatformInterface confirm: aString
  79. !
  80. prompt: aString
  81. ^ PlatformInterface prompt: aString
  82. !
  83. prompt: aString default: defaultString
  84. ^ PlatformInterface prompt: aString default: defaultString
  85. ! !
  86. InterfacingObject subclass: #Environment
  87. instanceVariableNames: ''
  88. package: 'Platform-Services'!
  89. !Environment commentStamp!
  90. I provide an unified entry point to manipulate Amber packages, classes and methods.
  91. Typical use cases include IDEs, remote access and restricting browsing.!
  92. !Environment methodsFor: 'accessing'!
  93. allSelectors
  94. ^ Smalltalk core allSelectors
  95. !
  96. availableClassNames
  97. ^ Smalltalk classes
  98. collect: [ :each | each name ]
  99. !
  100. availablePackageNames
  101. ^ Smalltalk packages
  102. collect: [ :each | each name ]
  103. !
  104. availableProtocolsFor: aClass
  105. | protocols |
  106. protocols := aClass protocols.
  107. aClass superclass ifNotNil: [ protocols addAll: (self availableProtocolsFor: aClass superclass) ].
  108. ^ protocols asSet asArray sort
  109. !
  110. classBuilder
  111. ^ ClassBuilder new
  112. !
  113. classNamed: aString
  114. ^ (Smalltalk globals at: aString asSymbol)
  115. ifNil: [ self error: 'Invalid class name' ]
  116. !
  117. classes
  118. ^ Smalltalk classes
  119. !
  120. doItReceiver
  121. ^ DoIt new
  122. !
  123. packages
  124. ^ Smalltalk packages
  125. !
  126. systemAnnouncer
  127. ^ (Smalltalk globals at: #SystemAnnouncer) current
  128. ! !
  129. !Environment methodsFor: 'actions'!
  130. commitPackage: aPackage onSuccess: aBlock onError: anotherBlock
  131. aPackage transport
  132. commitOnSuccess: aBlock
  133. onError: anotherBlock
  134. !
  135. copyClass: aClass to: aClassName
  136. (Smalltalk globals at: aClassName)
  137. ifNotNil: [ self error: 'A class named ', aClassName, ' already exists' ].
  138. ClassBuilder new copyClass: aClass named: aClassName
  139. !
  140. inspect: anObject
  141. Inspector inspect: anObject
  142. !
  143. moveClass: aClass toPackage: aPackageName
  144. | package |
  145. package := Package named: aPackageName.
  146. package ifNil: [ self error: 'Invalid package name' ].
  147. package == aClass package ifTrue: [ ^ self ].
  148. aClass package: package
  149. !
  150. moveMethod: aMethod toClass: aClassName
  151. | destinationClass |
  152. destinationClass := self classNamed: aClassName.
  153. destinationClass == aMethod methodClass ifTrue: [ ^ self ].
  154. aMethod methodClass isMetaclass ifTrue: [
  155. destinationClass := destinationClass class ].
  156. destinationClass
  157. compile: aMethod source
  158. protocol: aMethod protocol.
  159. aMethod methodClass
  160. removeCompiledMethod: aMethod
  161. !
  162. moveMethod: aMethod toProtocol: aProtocol
  163. aMethod protocol: aProtocol
  164. !
  165. removeClass: aClass
  166. Smalltalk removeClass: aClass
  167. !
  168. removeMethod: aMethod
  169. aMethod methodClass removeCompiledMethod: aMethod
  170. !
  171. removeProtocol: aString from: aClass
  172. (aClass methodsInProtocol: aString)
  173. do: [ :each | aClass removeCompiledMethod: each ]
  174. !
  175. renameClass: aClass to: aClassName
  176. (Smalltalk globals at: aClassName)
  177. ifNotNil: [ self error: 'A class named ', aClassName, ' already exists' ].
  178. ClassBuilder new renameClass: aClass to: aClassName
  179. !
  180. renamePackage: aPackageName to: aNewPackageName
  181. (Smalltalk globals at: aNewPackageName)
  182. ifNotNil: [ self error: 'A package named ', aNewPackageName, ' already exists' ].
  183. Smalltalk renamePackage: aPackageName to: aNewPackageName
  184. !
  185. renameProtocol: aString to: anotherString in: aClass
  186. (aClass methodsInProtocol: aString)
  187. do: [ :each | each protocol: anotherString ]
  188. !
  189. setClassCommentOf: aClass to: aString
  190. aClass comment: aString
  191. ! !
  192. !Environment methodsFor: 'compiling'!
  193. addInstVarNamed: aString to: aClass
  194. self classBuilder
  195. addSubclassOf: aClass superclass
  196. named: aClass name
  197. instanceVariableNames: (aClass instanceVariableNames copy add: aString; yourself)
  198. package: aClass package name
  199. !
  200. compileClassComment: aString for: aClass
  201. aClass comment: aString
  202. !
  203. compileClassDefinition: aString
  204. [ self evaluate: aString for: DoIt new ]
  205. on: Error
  206. do: [ :error | self alert: error messageText ]
  207. !
  208. compileMethod: sourceCode for: class protocol: protocol
  209. ^ class
  210. compile: sourceCode
  211. protocol: protocol
  212. ! !
  213. !Environment methodsFor: 'error handling'!
  214. evaluate: aBlock on: anErrorClass do: exceptionBlock
  215. "Evaluate a block and catch exceptions happening on the environment stack"
  216. aBlock tryCatch: [ :exception |
  217. (exception isKindOf: (self classNamed: anErrorClass name))
  218. ifTrue: [ exceptionBlock value: exception ]
  219. ifFalse: [ exception resignal ] ]
  220. ! !
  221. !Environment methodsFor: 'evaluating'!
  222. evaluate: aString for: anObject
  223. ^ Evaluator evaluate: aString for: anObject
  224. ! !
  225. !Environment methodsFor: 'services'!
  226. registerErrorHandler: anErrorHandler
  227. ErrorHandler register: anErrorHandler
  228. !
  229. registerFinder: aFinder
  230. Finder register: aFinder
  231. !
  232. registerInspector: anInspector
  233. Inspector register: anInspector
  234. !
  235. registerProgressHandler: aProgressHandler
  236. ProgressHandler register: aProgressHandler
  237. !
  238. registerTranscript: aTranscript
  239. Transcript register: aTranscript
  240. ! !
  241. Object subclass: #NullProgressHandler
  242. instanceVariableNames: ''
  243. package: 'Platform-Services'!
  244. !NullProgressHandler commentStamp!
  245. I am the default progress handler. I do not display any progress, and simply iterate over the collection.!
  246. !NullProgressHandler methodsFor: 'progress handling'!
  247. do: aBlock on: aCollection displaying: aString
  248. aCollection do: aBlock
  249. ! !
  250. NullProgressHandler class instanceVariableNames: 'current'!
  251. !NullProgressHandler class methodsFor: 'initialization'!
  252. initialize
  253. ProgressHandler registerIfNone: self new
  254. ! !
  255. Object subclass: #PlatformInterface
  256. instanceVariableNames: ''
  257. package: 'Platform-Services'!
  258. !PlatformInterface commentStamp!
  259. I am single entry point to UI and environment interface.
  260. My `initialize` tries several options (for now, browser environment only) to set myself up.
  261. ## API
  262. PlatformInterface alert: 'Hey, there is a problem'.
  263. PlatformInterface confirm: 'Affirmative?'.
  264. PlatformInterface prompt: 'Your name:'.
  265. PlatformInterface ajax: #{
  266. 'url' -> '/patch.js'. 'type' -> 'GET'. dataType->'script'
  267. }.!
  268. PlatformInterface class instanceVariableNames: 'worker'!
  269. !PlatformInterface class methodsFor: 'accessing'!
  270. globals
  271. <return (new Function('return this'))();>
  272. !
  273. setWorker: anObject
  274. worker := anObject
  275. ! !
  276. !PlatformInterface class methodsFor: 'actions'!
  277. ajax: anObject
  278. ^ worker
  279. ifNotNil: [ worker ajax: anObject ]
  280. ifNil: [ self error: 'ajax: not available' ]
  281. !
  282. alert: aString
  283. ^ worker
  284. ifNotNil: [ worker alert: aString ]
  285. ifNil: [ self error: 'alert: not available' ]
  286. !
  287. confirm: aString
  288. ^ worker
  289. ifNotNil: [ worker confirm: aString ]
  290. ifNil: [ self error: 'confirm: not available' ]
  291. !
  292. existsGlobal: aString
  293. ^ PlatformInterface globals
  294. at: aString
  295. ifPresent: [ true ]
  296. ifAbsent: [ false ]
  297. !
  298. prompt: aString
  299. ^ worker
  300. ifNotNil: [ worker prompt: aString ]
  301. ifNil: [ self error: 'prompt: not available' ]
  302. !
  303. prompt: aString default: defaultString
  304. ^ worker
  305. ifNotNil: [ worker prompt: aString default: defaultString ]
  306. ifNil: [ self error: 'prompt: not available' ]
  307. ! !
  308. !PlatformInterface class methodsFor: 'initialization'!
  309. initialize
  310. | candidate |
  311. super initialize.
  312. BrowserInterface ifNotNil: [
  313. candidate := BrowserInterface new.
  314. candidate isAvailable ifTrue: [ self setWorker: candidate. ^ self ]
  315. ]
  316. ! !
  317. Object subclass: #Service
  318. instanceVariableNames: ''
  319. package: 'Platform-Services'!
  320. !Service commentStamp!
  321. I implement the basic behavior for class registration to a service.
  322. See the `Transcript` class for a concrete service.
  323. ## API
  324. Use class-side methods `#register:` and `#registerIfNone:` to register classes to a specific service.!
  325. Service class instanceVariableNames: 'current'!
  326. !Service class methodsFor: 'accessing'!
  327. current
  328. ^ current
  329. ! !
  330. !Service class methodsFor: 'instance creation'!
  331. new
  332. self shouldNotImplement
  333. ! !
  334. !Service class methodsFor: 'registration'!
  335. register: anObject
  336. current := anObject
  337. !
  338. registerIfNone: anObject
  339. self current ifNil: [ self register: anObject ]
  340. ! !
  341. Service subclass: #ErrorHandler
  342. instanceVariableNames: ''
  343. package: 'Platform-Services'!
  344. !ErrorHandler commentStamp!
  345. I am the service used to handle Smalltalk errors.
  346. See `boot.js` `handleError()` function.
  347. Registered service instances must implement `#handleError:` to perform an action on the thrown exception.!
  348. !ErrorHandler class methodsFor: 'error handling'!
  349. handleError: anError
  350. self handleUnhandledError: anError
  351. !
  352. handleUnhandledError: anError
  353. anError wasHandled ifTrue: [ ^ self ].
  354. ^ self current handleError: anError
  355. ! !
  356. Service subclass: #Finder
  357. instanceVariableNames: ''
  358. package: 'Platform-Services'!
  359. !Finder commentStamp!
  360. I am the service responsible for finding classes/methods.
  361. __There is no default finder.__
  362. ## API
  363. Use `#browse` on an object to find it.!
  364. !Finder class methodsFor: 'finding'!
  365. findClass: aClass
  366. ^ self current findClass: aClass
  367. !
  368. findMethod: aCompiledMethod
  369. ^ self current findMethod: aCompiledMethod
  370. !
  371. findString: aString
  372. ^ self current findString: aString
  373. ! !
  374. Service subclass: #Inspector
  375. instanceVariableNames: ''
  376. package: 'Platform-Services'!
  377. !Inspector commentStamp!
  378. I am the service responsible for inspecting objects.
  379. The default inspector object is the transcript.!
  380. !Inspector class methodsFor: 'inspecting'!
  381. inspect: anObject
  382. ^ self current inspect: anObject
  383. ! !
  384. Service subclass: #ProgressHandler
  385. instanceVariableNames: ''
  386. package: 'Platform-Services'!
  387. !ProgressHandler commentStamp!
  388. I am used to manage progress in collection iterations, see `SequenceableCollection >> #do:displayingProgress:`.
  389. Registered instances must implement `#do:on:displaying:`.
  390. The default behavior is to simply iterate over the collection, using `NullProgressHandler`.!
  391. !ProgressHandler class methodsFor: 'progress handling'!
  392. do: aBlock on: aCollection displaying: aString
  393. self current do: aBlock on: aCollection displaying: aString
  394. ! !
  395. Service subclass: #Transcript
  396. instanceVariableNames: ''
  397. package: 'Platform-Services'!
  398. !Transcript commentStamp!
  399. I am a facade for Transcript actions.
  400. I delegate actions to the currently registered transcript.
  401. ## API
  402. Transcript
  403. show: 'hello world';
  404. cr;
  405. show: anObject.!
  406. !Transcript class methodsFor: 'instance creation'!
  407. open
  408. self current open
  409. ! !
  410. !Transcript class methodsFor: 'printing'!
  411. clear
  412. self current clear
  413. !
  414. cr
  415. self current show: String cr
  416. !
  417. inspect: anObject
  418. self show: anObject
  419. !
  420. show: anObject
  421. self current show: anObject
  422. ! !
  423. !AssociativeCollection methodsFor: '*Platform-Services'!
  424. inspectOn: anInspector
  425. | variables |
  426. variables := Dictionary new.
  427. variables at: '#self' put: self.
  428. variables at: '#keys' put: self keys.
  429. self keysAndValuesDo: [ :key :value |
  430. variables at: key put: value ].
  431. anInspector
  432. setLabel: self printString;
  433. setVariables: variables
  434. ! !
  435. !Collection methodsFor: '*Platform-Services'!
  436. inspectOn: anInspector
  437. | variables |
  438. variables := Dictionary new.
  439. variables at: '#self' put: self.
  440. self withIndexDo: [ :each :i |
  441. variables at: i put: each ].
  442. anInspector
  443. setLabel: self printString;
  444. setVariables: variables
  445. ! !
  446. !Date methodsFor: '*Platform-Services'!
  447. inspectOn: anInspector
  448. | variables |
  449. variables := Dictionary new.
  450. variables at: '#self' put: self.
  451. variables at: '#year' put: self year.
  452. variables at: '#month' put: self month.
  453. variables at: '#day' put: self day.
  454. variables at: '#hours' put: self hours.
  455. variables at: '#minutes' put: self minutes.
  456. variables at: '#seconds' put: self seconds.
  457. variables at: '#milliseconds' put: self milliseconds.
  458. anInspector
  459. setLabel: self printString;
  460. setVariables: variables
  461. ! !
  462. !JSObjectProxy methodsFor: '*Platform-Services'!
  463. inspectOn: anInspector
  464. | variables |
  465. variables := Dictionary new.
  466. variables at: '#self' put: self jsObject.
  467. anInspector setLabel: self printString.
  468. JSObjectProxy addObjectVariablesTo: variables ofProxy: self.
  469. anInspector setVariables: variables
  470. ! !
  471. !MethodContext methodsFor: '*Platform-Services'!
  472. inspectOn: anInspector
  473. | variables |
  474. variables := Dictionary new.
  475. variables at: '#self' put: self.
  476. variables at: '#home' put: self home.
  477. variables at: '#receiver' put: self receiver.
  478. variables at: '#selector' put: self selector.
  479. variables at: '#locals' put: self locals.
  480. self class instanceVariableNames do: [ :each |
  481. variables at: each put: (self instVarAt: each) ].
  482. anInspector
  483. setLabel: self printString;
  484. setVariables: variables
  485. ! !
  486. !Object methodsFor: '*Platform-Services'!
  487. inspectOn: anInspector
  488. | variables |
  489. variables := Dictionary new.
  490. variables at: '#self' put: self.
  491. self class allInstanceVariableNames do: [ :each |
  492. variables at: each put: (self instVarAt: each) ].
  493. anInspector
  494. setLabel: self printString;
  495. setVariables: variables
  496. ! !
  497. !SequenceableCollection methodsFor: '*Platform-Services'!
  498. do: aBlock displayingProgress: aString
  499. ProgressHandler
  500. do: aBlock
  501. on: self
  502. displaying: aString
  503. ! !
  504. !Set methodsFor: '*Platform-Services'!
  505. inspectOn: anInspector
  506. | variables i |
  507. variables := Dictionary new.
  508. variables at: '#self' put: self.
  509. i := 1.
  510. self do: [ :each |
  511. variables at: i put: each.
  512. i := i + 1 ].
  513. anInspector
  514. setLabel: self printString;
  515. setVariables: variables
  516. ! !
  517. !String methodsFor: '*Platform-Services'!
  518. inspectOn: anInspector
  519. | label |
  520. super inspectOn: anInspector.
  521. self printString size > 30
  522. ifTrue: [ label := (self printString copyFrom: 1 to: 30), '...''' ]
  523. ifFalse: [ label := self printString ].
  524. anInspector setLabel: label
  525. ! !