Platform-Services.st 16 KB

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