From a65083f78d5945fb8c80915bedad85fb42dea454 Mon Sep 17 00:00:00 2001 From: Tom Beckmann Date: Fri, 22 Sep 2023 10:46:57 +0200 Subject: [PATCH] dap: first implementation of the debug adapter protocol --- .../SBLSPTCPTransport.class.st | 14 +- .../SBTSDebugAdapterClient.class.st | 331 ++++++++++++++++++ .../SBTSDebugger.class.st | 216 ++++++++++++ .../SBTSDebuggerFrame.class.st | 39 +++ .../SBTSFileParseNode.class.st | 6 + .../SBTSLanguageClient.class.st | 43 ++- .../SBTSParseNode.class.st | 9 +- .../Sandblocks-TreeSitter/SBTSQuery.class.st | 5 +- .../SBTSRemoteObject.class.st | 43 +++ 9 files changed, 690 insertions(+), 16 deletions(-) create mode 100644 packages/Sandblocks-TreeSitter/SBTSDebugAdapterClient.class.st create mode 100644 packages/Sandblocks-TreeSitter/SBTSDebugger.class.st create mode 100644 packages/Sandblocks-TreeSitter/SBTSDebuggerFrame.class.st create mode 100644 packages/Sandblocks-TreeSitter/SBTSRemoteObject.class.st diff --git a/packages/Sandblocks-TreeSitter/SBLSPTCPTransport.class.st b/packages/Sandblocks-TreeSitter/SBLSPTCPTransport.class.st index 0641395..fb81062 100644 --- a/packages/Sandblocks-TreeSitter/SBLSPTCPTransport.class.st +++ b/packages/Sandblocks-TreeSitter/SBLSPTCPTransport.class.st @@ -31,12 +31,24 @@ SBLSPTCPTransport >> handleDataFrom: aStream [ languageClient handleMessage: message ] +{ #category : #'as yet unclassified' } +SBLSPTCPTransport >> host [ + + ^ host +] + { #category : #'as yet unclassified' } SBLSPTCPTransport >> host: aString [ host := aString ] +{ #category : #'as yet unclassified' } +SBLSPTCPTransport >> port [ + + ^ port +] + { #category : #'as yet unclassified' } SBLSPTCPTransport >> port: aNumber [ @@ -48,7 +60,7 @@ SBLSPTCPTransport >> start [ super start. - stream := [SocketStream openConnectionToHostNamed: '127.0.0.1' port: port] on: ConnectionRefused do: [:e | ^ self]. + stream := [SocketStream openConnectionToHostNamed: host port: port] on: ConnectionRefused do: [:e | ^ self]. stream timeout: 100000. [[stream atEnd] whileFalse: [self handleDataFrom: stream]] fork diff --git a/packages/Sandblocks-TreeSitter/SBTSDebugAdapterClient.class.st b/packages/Sandblocks-TreeSitter/SBTSDebugAdapterClient.class.st new file mode 100644 index 0000000..d0ce1bf --- /dev/null +++ b/packages/Sandblocks-TreeSitter/SBTSDebugAdapterClient.class.st @@ -0,0 +1,331 @@ +Class { + #name : #SBTSDebugAdapterClient, + #superclass : #SBTSLanguageClient, + #instVars : [ + 'launchConfig', + 'session', + 'initializationPromise', + 'parent' + ], + #category : #'Sandblocks-TreeSitter-LanguageClient' +} + +{ #category : #requests } +SBTSDebugAdapterClient >> attach: arguments do: aBlock [ + + self sendRequest: 'attach' params: arguments do: [:res | aBlock value] blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> breakpointLocationsIn: aFilePathString at: aLineNumber [ + + ^ self + sendBlockingRequest: 'breakpointLocations' + params: (Dictionary newFrom: {'source' -> (Dictionary newFrom: {'path' -> aFilePathString}). 'line' -> aLineNumber}) + do: [:r | r breakpoints] +] + +{ #category : #requests } +SBTSDebugAdapterClient >> close [ + + [self disconnect] on: ConnectionTimedOut, SocketPrimitiveFailed, Error do: []. + super close +] + +{ #category : #requests } +SBTSDebugAdapterClient >> continue: aThreadIdNumber [ + + self + sendRequest: 'continue' + params: (Dictionary newFrom: {'threadId' -> aThreadIdNumber}) + do: [:res | ] + blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> disconnect [ + + self sendRequest: 'disconnect' params: Dictionary new do: [:res | ] blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> evaluate: aString in: aFrameId [ + + ^ [ + self + sendBlockingRequest: 'evaluate' + params: (Dictionary newFrom: {'expression' -> aString. 'context' -> 'repl'. 'frameId' -> aFrameId}) + do: [:r | r]] + on: BrokenPromise + do: [:p | self error: p reason] +] + +{ #category : #communication } +SBTSDebugAdapterClient >> formatRequest: aString params: anObject seq: myId [ + + ^ Dictionary newFrom: {'type' -> 'request'. 'seq' -> myId. 'command' -> aString. 'arguments' -> anObject} +] + +{ #category : #requests } +SBTSDebugAdapterClient >> gotoTargetsIn: aFilePathString at: aLineNumber [ + + ^ self + sendBlockingRequest: 'gotoTargets' + params: (Dictionary newFrom: {'source' -> (Dictionary newFrom: {'path' -> aFilePathString}). 'line' -> aLineNumber}) + do: [:r | r] +] + +{ #category : #communication } +SBTSDebugAdapterClient >> handleMessage: aJsonObject [ + + aJsonObject type = 'event' ifTrue: [ + aJsonObject event + caseOf: { + [#initialized] -> [self sendConfiguration]. + [#output] -> [aJsonObject body category ~= 'telemetry' ifTrue: [self triggerUIEvent: #output with: aJsonObject body]]. + [#terminated] -> [self triggerUIEvent: #terminated]. + [#thread] -> [self triggerUIEvent: #thread]. + [#stopped] -> [self triggerUIEvent: #stopped with: aJsonObject body]. + [#continued] -> [self triggerUIEvent: #continued with: aJsonObject body]. + [#loadedSource] -> []} + otherwise: [Transcript showln: ('unhandled event: {1}' format: {aJsonObject event})]]. + + aJsonObject type = 'request' ifTrue: [ + aJsonObject command + caseOf: { + [#startDebugging] -> [ + session := SBTSDebugAdapterClient new + initializeFor: aJsonObject arguments configuration transport: (SBLSPTCPTransport new + host: transport host; + port: transport port); + parent: self. + self triggerUIEvent: #session with: session]} + otherwise: [self log: ('unhandled request: {1}' format: {aJsonObject command})]]. + + aJsonObject type = 'response' ifTrue: [ + pending + at: aJsonObject request_seq + ifPresent: [:promise | + pending removeKey: aJsonObject request_seq. + aJsonObject success ifFalse: [ | error | + error := aJsonObject at: 'message' ifAbsent: [(aJsonObject body at: #error) format]. + SBToggledCode comment: '' active: 0 do: {[self onUIThread: [self error: error]]}. + ^ promise rejectWith: error]. + promise resolveWith: aJsonObject body] + ifAbsent: [self log: {'unknown message'. aJsonObject}]] +] + +{ #category : #communication } +SBTSDebugAdapterClient >> initializeFor: aLaunchConfig transport: aTransport [ + + transport := aTransport languageClient: self. + launchConfig := aLaunchConfig. + + transport start. + + transport connected + ifTrue: [ + self sendInitializeDo: [ + self launch: launchConfig do: [ + self triggerEvent: #launched. + self triggerUIEvent: #session with: self]]] + ifFalse: [self error: 'Could not connect'] +] + +{ #category : #requests } +SBTSDebugAdapterClient >> launch: arguments do: aBlock [ + + self sendRequest: 'launch' params: arguments do: [:res | aBlock value] blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> next: aThreadIdNumber [ + + self + sendRequest: 'next' + params: (Dictionary newFrom: {'threadId' -> aThreadIdNumber}) + do: [:res | ] + blocking: false +] + +{ #category : #accessing } +SBTSDebugAdapterClient >> parent [ + + ^ parent +] + +{ #category : #accessing } +SBTSDebugAdapterClient >> parent: aSession [ + + parent := aSession +] + +{ #category : #requests } +SBTSDebugAdapterClient >> pause: aThreadIdNumber [ + + self + sendRequest: 'pause' + params: (Dictionary newFrom: {'threadId' -> aThreadIdNumber}) + do: [:res | ] + blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> restartFrame: aFrameNumber [ + + self + sendRequest: 'restartFrame' + params: (Dictionary newFrom: {'frameId' -> aFrameNumber}) + do: [:res | ] + blocking: false +] + +{ #category : #communication } +SBTSDebugAdapterClient >> sendBlockingResponse: aString to: aNumber params: anObject [ + + self internalSend: [:myId | Dictionary newFrom: {#seq -> myId. #'request_seq' -> aNumber. 'type' -> 'response'. 'command' -> aString. 'body' -> anObject}] +] + +{ #category : #communication } +SBTSDebugAdapterClient >> sendConfiguration [ + + self + setBreakpoints: {Dictionary newFrom: {'line' -> 6. 'column' -> 7. 'logMessage' -> 'hit! {obj}'}} + in: '/home/tom/Code/squeak/test.js'. + + (serverCapabilities at: #exceptionBreakpointFilters ifAbsent: [#()]) ifNotEmpty: [:filters | + self + sendAsyncRequest: 'setExceptionBreakpoints' + params: (Dictionary newFrom: {'filters' -> (filters collect: [:filter | filter filter])}) + do: [:r | self inform: r]]. + + ^ self sendAsyncRequest: 'configurationDone' params: Dictionary new do: [:res | ] +] + +{ #category : #communication } +SBTSDebugAdapterClient >> sendInitializeDo: aBlock [ + + initializationPromise := self + sendRequest: 'initialize' + params: (Dictionary newFrom: { + 'clientID' -> 'sandblocks'. + 'clientName' -> 'sandblocks'. + 'adapterID' -> 'sandblocks-dap'. + 'pathFormat' -> 'path'. + 'columnsStartAt1' -> true. + 'linesStartAt1' -> true. + 'supportsStartDebuggingRequest' -> true. + 'supportsProgressReporting' -> true. + 'supportsInvalidatedEvent' -> true. + 'supportsValueFormattingOptions' -> true}) + do: [:response | + serverCapabilities := response. + aBlock value] + blocking: false +] + +{ #category : #accessing } +SBTSDebugAdapterClient >> session [ + + ^ session ifNil: [self] +] + +{ #category : #requests } +SBTSDebugAdapterClient >> setBreakpoints: aCollection in: aPathString [ + + self + sendRequest: 'setBreakpoints' + params: (Dictionary newFrom: {'breakpoints' -> aCollection. 'source' -> (Dictionary newFrom: {'path' -> aPathString})}) + do: [:res | ] + blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> source: aPathString [ + + ^ self + sendBlockingRequest: 'source' + params: (Dictionary newFrom: {'source' -> (Dictionary newFrom: {'path' -> aPathString})}) + do: [:r | r] +] + +{ #category : #requests } +SBTSDebugAdapterClient >> stackTraceForThread: aNumber [ + + ^ self + sendBlockingRequest: 'stackTrace' + params: (Dictionary newFrom: {'threadId' -> aNumber}) + do: [:r | r stackFrames] +] + +{ #category : #requests } +SBTSDebugAdapterClient >> stepBack: aThreadIdNumber [ + + self + sendRequest: 'stepBack' + params: (Dictionary newFrom: {'threadId' -> aThreadIdNumber}) + do: [:res | ] + blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> stepIn: aThreadIdNumber [ + + self + sendRequest: 'stepIn' + params: (Dictionary newFrom: {'threadId' -> aThreadIdNumber}) + do: [:res | ] + blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> stepInTargetsIn: aFrameId [ + + ^ self + sendBlockingRequest: 'stepInTargets' + params: (Dictionary newFrom: {'frameId' -> aFrameId}) + do: [:r | r targets] +] + +{ #category : #requests } +SBTSDebugAdapterClient >> stepOut: aThreadIdNumber [ + + self + sendRequest: 'stepOut' + params: (Dictionary newFrom: {'threadId' -> aThreadIdNumber}) + do: [:res | ] + blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> terminate [ + + self sendRequest: 'terminate' params: Dictionary new do: [:res | ] blocking: false +] + +{ #category : #requests } +SBTSDebugAdapterClient >> threads [ + + ^ self sendBlockingRequest: 'threads' params: Dictionary new do: [:r | r threads] +] + +{ #category : #helpers } +SBTSDebugAdapterClient >> triggerUIEvent: aSymbol [ + + self onUIThread: [self triggerEvent: aSymbol] +] + +{ #category : #helpers } +SBTSDebugAdapterClient >> triggerUIEvent: aSymbol with: anObject [ + + self onUIThread: [self triggerEvent: aSymbol with: anObject] +] + +{ #category : #requests } +SBTSDebugAdapterClient >> variables: aNumber [ + + ^ self + sendBlockingRequest: 'variables' + params: (Dictionary newFrom: {'variablesReference' -> aNumber}) + do: [:r | r variables] +] diff --git a/packages/Sandblocks-TreeSitter/SBTSDebugger.class.st b/packages/Sandblocks-TreeSitter/SBTSDebugger.class.st new file mode 100644 index 0000000..e1fb13b --- /dev/null +++ b/packages/Sandblocks-TreeSitter/SBTSDebugger.class.st @@ -0,0 +1,216 @@ +Class { + #name : #SBTSDebugger, + #superclass : #SBBlock, + #instVars : [ + 'client', + 'frames', + 'sourceView', + 'pauseContinueButton', + 'paused', + 'currentLocation', + 'output', + 'selectedFrameId' + ], + #category : #'Sandblocks-TreeSitter-LanguageClient' +} + +{ #category : #'as yet unclassified' } +SBTSDebugger >> continued [ + + paused := false. + currentLocation ifNotNil: #detach. + pauseContinueButton firstSubmorph changeIconName: #iconPause +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> defaultThread [ + + ^ client threads first id +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> evaluate: aBlock [ + + | obj | + obj := client evaluate: aBlock sourceString in: selectedFrameId. + ^ self resolveVariable: obj maxLevel: 3 +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> initialize [ + + super initialize. + + client := SBTSDebugAdapterClient new + initializeFor: (Dictionary newFrom: { + 'type' -> 'pwa-node'. + 'stopOnEntry' -> true. + 'program' -> '/home/tom/Code/squeak/test.js'. + 'cwd' -> '/home/tom/Code/squeak'}) + transport: (SBLSPTCPTransport new + host: 'localhost'; + port: 5678). + + paused := false. + + client when: #session evaluate: [:session | + client := session. + client when: #stopped send: #stopped to: self. + client when: #continued send: #continued to: self. + client when: #terminated send: #terminated to: self. + client when: #output send: #output: to: self]. + + self + cellGap: 4; + hResizing: #rigid; + vResizing: #rigid; + layoutInset: 8; + extent: 300 @ 300; + attachDecorator: SBResizableDecorator new; + attachDecorator: SBForceMoveDecorator newConfigured; + listDirection: #topToBottom; + changeTableLayout; + addMorphBack: (ScrollPane new + in: [:s | + s scroller + addMorphBack: (frames := SBColumn new hResizing: #spaceFill); + hResizing: #spaceFill; + changeTableLayout. + s]; + hResizing: #spaceFill; + vResizing: #spaceFill); + addMorphBack: (SBRow new + cellGap: 2; + addMorphBack: (SBButton new icon: SBIcon iconArrowRight do: [client next: self defaultThread]); + addMorphBack: (SBButton new icon: SBIcon iconArrowDown do: [client stepIn: self defaultThread]); + addMorphBack: (SBButton new icon: SBIcon iconArrowUp do: [client stepOut: self defaultThread]); + addMorphBack: (pauseContinueButton := SBButton new + icon: SBIcon iconPlay + do: [paused ifTrue: [client continue: self defaultThread] ifFalse: [client pause: self defaultThread]]); + addMorphBack: (SBButton new icon: SBIcon iconStop do: [client terminate])); + addMorphBack: (ScrollPane new + in: [:s | + sourceView := s scroller. + s]; + hResizing: #spaceFill; + vResizing: #spaceFill); + addMorphBack: (SBStringMorph new + contents: 'Output:'; + bold); + addMorphBack: (ScrollPane new + in: [:s | + s scroller + addMorphBack: (output := SBColumn new hResizing: #spaceFill); + hResizing: #spaceFill; + changeTableLayout. + s]; + hResizing: #spaceFill; + vResizing: #spaceFill) +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> isArtefact [ + + ^ true +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> outOfWorld: aWorld [ + + super outOfWorld: aWorld. + + client close +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> output: anObject [ + + output addMorphBack: (SBBlock new + addMorphBack: (SBMultilineOwnTextMorph new contents: anObject output withoutTrailingBlanks); + hResizing: #spaceFill; + vResizing: #shrinkWrap; + changeTableLayout) +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> reloadArtefact [ + + + self updateAll +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> resolveVariable: aVariable maxLevel: aNumber [ + + ^ (aVariable variablesReference > 0 and: [aNumber > 0]) + ifTrue: [ | wrapper | + wrapper := SBTSRemoteObject new + type: aVariable type; + value: aVariable value. + (client variables: aVariable variablesReference) do: [:variable | wrapper at: variable name put: (self resolveVariable: variable maxLevel: aNumber - 1)]. + wrapper] + ifFalse: [aVariable value] +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> selectFrame: aFrame [ + + frames childSandblocks + detect: [:f | f id = selectedFrameId] + ifFound: [:f | f detachDecorators: SBHighlightDecorator]. + + selectedFrameId := aFrame id. + + frames childSandblocks + detect: [:f | f id = selectedFrameId] + ifFound: [:f | f attachDecorator: SBHighlightDecorator new]. + + sourceView + removeAllMorphs; + addMorphBack: (SBJavascript parse: (client source: aFrame source path) content); + fullBounds. + + sourceView firstSubmorph + allBlocksDetect: [:b | b range start line + 1 = aFrame line and: [b range start column + 1 = aFrame column]] + ifFound: [:current | + currentLocation ifNotNil: #detach. + current attachDecorator: (currentLocation := SBErrorDecorator new). + current ensureVisible] + ifNone: [] +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> stopped [ + + paused := true. + pauseContinueButton firstSubmorph changeIconName: #iconPlay. + self updateAll +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> terminated [ + + currentLocation ifNotNil: #detach. + self submorphs second hide +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> updateAll [ + + self updateFrames +] + +{ #category : #'as yet unclassified' } +SBTSDebugger >> updateFrames [ + + | list | + frames removeAllMorphs. + list := client stackTraceForThread: self defaultThread. + list do: [:frame | + frames addMorphBack: (SBTSDebuggerFrame new + for: frame; + when: #restart send: #restartFrame: to: client; + when: #selected send: #selectFrame: to: self)]. + + self selectFrame: (list detect: [:f | f id = selectedFrameId] ifFound: [:f | f] ifNone: [list first]) +] diff --git a/packages/Sandblocks-TreeSitter/SBTSDebuggerFrame.class.st b/packages/Sandblocks-TreeSitter/SBTSDebuggerFrame.class.st new file mode 100644 index 0000000..70f82bc --- /dev/null +++ b/packages/Sandblocks-TreeSitter/SBTSDebuggerFrame.class.st @@ -0,0 +1,39 @@ +Class { + #name : #SBTSDebuggerFrame, + #superclass : #SBBlock, + #instVars : [ + 'frame' + ], + #category : #'Sandblocks-TreeSitter-LanguageClient' +} + +{ #category : #'as yet unclassified' } +SBTSDebuggerFrame >> for: aFrame [ + + self + changeTableLayout; + hResizing: #spaceFill; + vResizing: #shrinkWrap; + listDirection: #leftToRight; + cellGap: 8; + addMorphBack: (SBStringMorph new contents: aFrame name). + + frame := aFrame. + + aFrame canRestart == true ifTrue: [ + self addMorphBack: (SBButton new + icon: SBIcon iconRefresh do: [self triggerEvent: #restart with: aFrame id]; + makeSmall)] +] + +{ #category : #'as yet unclassified' } +SBTSDebuggerFrame >> id [ + + ^ frame id +] + +{ #category : #'as yet unclassified' } +SBTSDebuggerFrame >> wasSelected [ + + self triggerEvent: #selected with: frame +] diff --git a/packages/Sandblocks-TreeSitter/SBTSFileParseNode.class.st b/packages/Sandblocks-TreeSitter/SBTSFileParseNode.class.st index 749bfe1..6131f4d 100644 --- a/packages/Sandblocks-TreeSitter/SBTSFileParseNode.class.st +++ b/packages/Sandblocks-TreeSitter/SBTSFileParseNode.class.st @@ -7,6 +7,12 @@ Class { #category : #'Sandblocks-TreeSitter-Parser' } +{ #category : #'as yet unclassified' } +SBTSFileParseNode >> range [ + + ^ range ifNil: [super range] +] + { #category : #'as yet unclassified' } SBTSFileParseNode >> range: aRange [ diff --git a/packages/Sandblocks-TreeSitter/SBTSLanguageClient.class.st b/packages/Sandblocks-TreeSitter/SBTSLanguageClient.class.st index 5734058..dde2f07 100644 --- a/packages/Sandblocks-TreeSitter/SBTSLanguageClient.class.st +++ b/packages/Sandblocks-TreeSitter/SBTSLanguageClient.class.st @@ -44,10 +44,16 @@ SBTSLanguageClient >> connected [ ^ transport connected ] +{ #category : #'as yet unclassified' } +SBTSLanguageClient >> formatRequest: aString params: anObject seq: myId [ + + ^ Dictionary newFrom: {'jsonrpc' -> '2.0'. 'id' -> myId. 'method' -> aString. 'params' -> anObject} +] + { #category : #'as yet unclassified' } SBTSLanguageClient >> handleMessage: aJsonObject [ - (aJsonObject includesKey: 'method') + (aJsonObject includesKey: 'event') ifTrue: [self onUIThread: [self handleServerMessage: aJsonObject]] ifFalse: [ pending @@ -69,33 +75,46 @@ SBTSLanguageClient >> handleServerMessage: aJsonObject [ ] { #category : #'as yet unclassified' } -SBTSLanguageClient >> initializeFor: aDirectory onServerMessageDo: aBlock onReady: anotherBlock transport: aTransport [ +SBTSLanguageClient >> initialize [ super initialize. - transport := aTransport languageClient: self. serverCapabilities := Dictionary new. - serverMessageHandler := aBlock. pending := Dictionary new. + lastRequestId := 0 +] + +{ #category : #'as yet unclassified' } +SBTSLanguageClient >> initializeFor: aDirectory onServerMessageDo: aBlock onReady: anotherBlock transport: aTransport [ + + transport := aTransport languageClient: self. + serverMessageHandler := aBlock. projectDirectory := aDirectory. - lastRequestId := 0. transport start. - transport connected ifTrue: [self sendInitializeDo: anotherBlock] + transport connected + ifTrue: [self sendInitializeDo: anotherBlock] + ifFalse: [self error: 'Could not connect'] ] { #category : #'as yet unclassified' } -SBTSLanguageClient >> internalSendRequest: aString params: anObject [ +SBTSLanguageClient >> internalSend: aBlock [ | myId promise | myId := lastRequestId := lastRequestId + 1. promise := Promise new. pending at: myId put: promise. - self send: (Dictionary newFrom: {'jsonrpc' -> '2.0'. 'id' -> myId. 'method' -> aString. 'params' -> anObject}). + self send: (aBlock value: myId). ^ promise ] +{ #category : #'as yet unclassified' } +SBTSLanguageClient >> internalSendRequest: aString params: anObject [ + + ^ self internalSend: [:myId | self formatRequest: aString params: anObject seq: myId] +] + { #category : #'as yet unclassified' } SBTSLanguageClient >> log: anObject [ @@ -135,13 +154,15 @@ SBTSLanguageClient >> send: aJsonObject [ { #category : #'as yet unclassified' } SBTSLanguageClient >> sendAsyncRequest: aString params: anObject do: aBlock [ - (self internalSendRequest: aString params: anObject) then: [:response | self onUIThread: [aBlock value: response]] + ^ (self internalSendRequest: aString params: anObject) then: [:response | + self onUIThread: [aBlock value: response]. + response] ] { #category : #'as yet unclassified' } SBTSLanguageClient >> sendBlockingRequest: aString params: anObject do: aBlock [ - aBlock value: (self internalSendRequest: aString params: anObject) wait + ^ aBlock value: (self internalSendRequest: aString params: anObject) wait ] { #category : #'as yet unclassified' } @@ -176,7 +197,7 @@ SBTSLanguageClient >> sendNotification: aString params: anObject [ { #category : #'as yet unclassified' } SBTSLanguageClient >> sendRequest: aString params: anObject do: aBlock blocking: aBoolean [ - aBoolean + ^ aBoolean ifTrue: [self sendBlockingRequest: aString params: anObject do: aBlock] ifFalse: [self sendAsyncRequest: aString params: anObject do: aBlock] ] diff --git a/packages/Sandblocks-TreeSitter/SBTSParseNode.class.st b/packages/Sandblocks-TreeSitter/SBTSParseNode.class.st index 6b03196..4630c7b 100644 --- a/packages/Sandblocks-TreeSitter/SBTSParseNode.class.st +++ b/packages/Sandblocks-TreeSitter/SBTSParseNode.class.st @@ -31,7 +31,8 @@ SBTSParseNode >> buildCopyEmbeds: aBoolean [ [#block] -> [ SBTSBlock new addAllMorphs: (contents collect: [:b | b buildCopyEmbeds: aBoolean]); - slot: slot]. + slot: slot; + range: self range]. [#unknown] -> [SBTSUnknownBlock new slot: slot]. [#label] -> [ SBTSLabel new @@ -199,6 +200,12 @@ SBTSParseNode >> printOn: aStream [ aStream nextPut: $) ] +{ #category : #'as yet unclassified' } +SBTSParseNode >> range [ + + ^ SBTSRange start: (SBTSPosition line: 0 character: 0) end: (SBTSPosition line: 0 character: 0) +] + { #category : #'as yet unclassified' } SBTSParseNode >> recursiveNodeCount [ diff --git a/packages/Sandblocks-TreeSitter/SBTSQuery.class.st b/packages/Sandblocks-TreeSitter/SBTSQuery.class.st index 89126ab..c7030ba 100644 --- a/packages/Sandblocks-TreeSitter/SBTSQuery.class.st +++ b/packages/Sandblocks-TreeSitter/SBTSQuery.class.st @@ -3,7 +3,6 @@ Class { #superclass : #Object, #instVars : [ 'stream', - 'captures', 'expressions', 'predicates' ], @@ -20,7 +19,7 @@ SBTSQuery >> execute: aString against: aBlock capturesDo: aClosure [ { #category : #'as yet unclassified' } SBTSQuery >> executeAgainst: aBlock capturesDo: aClosure [ - | ret target | + | ret target captures | target := aBlock. captures := Dictionary new. @@ -43,7 +42,7 @@ SBTSQuery >> executeAgainst: aBlock capturesDo: aClosure [ { #category : #'as yet unclassified' } SBTSQuery >> executeCaptureAgainst: aBlock [ - | ret target | + | ret target captures | target := aBlock. captures := OrderedCollection new. diff --git a/packages/Sandblocks-TreeSitter/SBTSRemoteObject.class.st b/packages/Sandblocks-TreeSitter/SBTSRemoteObject.class.st new file mode 100644 index 0000000..22a7eb9 --- /dev/null +++ b/packages/Sandblocks-TreeSitter/SBTSRemoteObject.class.st @@ -0,0 +1,43 @@ +Class { + #name : #SBTSRemoteObject, + #superclass : #Dictionary, + #instVars : [ + 'type', + 'value' + ], + #category : #'Sandblocks-TreeSitter-LanguageClient' +} + +{ #category : #'as yet unclassified' } +SBTSRemoteObject >> printOn: aStream [ + + aStream nextPutAll: self type. + + self type = self value ifFalse: [ + aStream nextPut: $ . + aStream nextPutAll: self value] +] + +{ #category : #'as yet unclassified' } +SBTSRemoteObject >> type [ + + ^ type +] + +{ #category : #'as yet unclassified' } +SBTSRemoteObject >> type: aString [ + + type := aString +] + +{ #category : #'as yet unclassified' } +SBTSRemoteObject >> value [ + + ^ value +] + +{ #category : #'as yet unclassified' } +SBTSRemoteObject >> value: aString [ + + value := aString +]