Hello! As a beginner, I am trying to learn Squeak/Smalltalk by implementing a way for to insert unicode characters by replacing targets in a string before the cursor when needed while writing in, for example, a Workspace. Let's say that you write in a Workspace these characters: '->' then you hit ALT-TAB and '->' get replaced by the character: '→'. How to implemente such a thing? I picture a thing called a "Morph" (I guess?) that holds the string that I'm updating by typing on my keyboard (like a Workspace). This morph logs things that happens to it in an output stream of events. An object called: "SnippetExpander" reads this stream of event and when appropriate asks the morph more information (e.g. what are the last N characters before the cursor). Depeding on the reply, the SnippetExpander asks the morph to update the string. I imagine messages, observers and streams behaving like in http://reactivex.io. Here are a few questions that I stumbled upon: SnippetExpander tries to observe whatever object has focus. What does it mean to "have" focus? How to know what has focus? What does it mean to "observe"? When an object has focus and is the type of object you can type text in (let's name that thing: focusedTextObject) then SnippetExpander observes its output messages. How to test an object and know if you can type text in it? When SnippetExpander observes that the ALT-TAB key has been entered, then SnippetExpander asks the focusedTextObject the last N characters before point. If needed, SnippetExpander asks focusedTextObject to replace the last N characters by a replacement string. Am I doing it wrong? Bellow, the code of SnippetExpander wrote so far that I "filedOut". Thx! ==== 888-SnippetExpander.st ====================== Object subclass: #SnippetExpander instanceVariableNames: 'snippetsAndExpansions' classVariableNames: '' poolDictionaries: '' category: '888-SnippetExpander'! !SnippetExpander commentStamp: '888 6/2/2017 17:03' prior: 0! I check last characters before the cursor and decide to replace them by an other sequence of characters.! !SnippetExpander methodsFor: 'behavior' stamp: '888 6/3/2017 01:13'! expandSnippet: s ^ [(snippetsAndExpansions at: s) at: 2] on: KeyNotFound do: [ :exception | Transcript open; show: 'I could not find a snippet: `', s, '` to expand.'; cr. ].! ! !SnippetExpander methodsFor: 'behavior' stamp: '888 6/3/2017 01:48'! forgetExpansion: e (snippetsAndExpansions select: [ :v | (v at: 2) = e ]) keysDo: [ :key | snippetsAndExpansions removeKey: key ].! ! !SnippetExpander methodsFor: 'behavior' stamp: '888 6/3/2017 01:34'! forgetSnippet: s snippetsAndExpansions removeKey: s ifAbsent: [ ^ self ].! ! !SnippetExpander methodsFor: 'behavior' stamp: '888 6/3/2017 01:23'! learnSnippet: s expansion: e "The next time the last characters behind the cursor match s, replace the match by the expansion e." snippetsAndExpansions at: s ifPresent: [ :value | Transcript open; show: 'Snippet ', s, ' is already associated to the expansion: ', (value at: 2); cr; show: 'A snippet cannot be ambiguous.'; cr. ]. snippetsAndExpansions add: (Array braceWith: s with: e). ! ! !SnippetExpander methodsFor: 'initialization' stamp: '888 6/3/2017 00:27'! initialize super initialize. snippetsAndExpansions := KeyedSet new. snippetsAndExpansions keyBlock: [ :e | e at: 1]. ! ! TestCase subclass: #SnippetExpanderTest instanceVariableNames: 'snippetExpander' classVariableNames: '' poolDictionaries: '' category: '888-SnippetExpander'! !SnippetExpanderTest methodsFor: 'as yet unclassified' stamp: '888 6/2/2017 22:49'! setUp snippetExpander := SnippetExpander new.! ! !SnippetExpanderTest methodsFor: 'as yet unclassified' stamp: '888 6/3/2017 01:50'! testBehavior "self run: #testBehavior" | t | snippetExpander learnSnippet: 'a' expansion: 'b'. self assert: (snippetExpander expandSnippet: 'a') = 'b'. snippetExpander forgetSnippet: 'a'. t := snippetExpander expandSnippet: 'a'. self assert: (t isMemberOf: TranscriptStream). t closeAllViews. snippetExpander learnSnippet: 'a' expansion: 'b'. snippetExpander learnSnippet: 'c' expansion: 'b'. snippetExpander forgetExpansion: 'b'. t := snippetExpander expandSnippet: 'a'. self assert: (t isMemberOf: TranscriptStream). t := snippetExpander expandSnippet: 'b'. self assert: (t isMemberOf: TranscriptStream). t closeAllViews.! ! Object subclass: #UniqueSnippetExpander instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: '888-SnippetExpander'! !UniqueSnippetExpander commentStamp: '888 6/3/2017 11:50' prior: 0! I hold the unique instance of SnippetExpander in use, outside of tests, to have only one collection of snippets to expansions associations.! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! UniqueSnippetExpander class instanceVariableNames: 'uniqueInstance'! !UniqueSnippetExpander class methodsFor: 'as yet unclassified' stamp: '888 6/3/2017 01:55'! uniqueInstance uniqueInstance ifNil: [ uniqueInstance := SnippetExpander new. ]. ^ uniqueInstance.! ! _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
> Hello!
> > As a beginner, I am trying to learn Squeak/Smalltalk by implementing a way for > to insert unicode characters by replacing targets in a string before the cursor > when needed while writing in, for example, a Workspace. You can do it, but many small details are involved. That makes it complicated. Not difficult but complicated. Time consuming. How much time and effort are you willing to spend to figure it all out? > Let's say that you write in a Workspace these characters: '->' then you hit > ALT-TAB and '->' get replaced by the character: '→'. How to implemente such a > thing? The shortcuts you could use are Alt-key and Shift-Alt-key. Many are taken, but you can find a few unused or re-assign those you do not use. Have a look in: ---- TextEditor class>>initializeCmdKeyShortcuts SmalltalkEditor class>>initializeCmdKeyShortcuts TextEditor class>>initializeShiftCmdKeyShortcuts SmalltalkEditor class>>initializeShiftCmdKeyShortcuts ---- > I picture a thing called a "Morph" (I guess?) that holds the string that I'm > updating by typing on my keyboard (like a Workspace). Things are more complicated. The Workspace window has a model, a Workspace. The model holds the string. The window is a Morph subclass. > This morph logs things that happens to it in an output stream of events. > An object called: "SnippetExpander" reads this stream of event and when > appropriate asks the morph more information (e.g. what are the last N > characters before the cursor). Depeding on the reply, the > SnippetExpander asks the morph to update the string. > > I imagine messages, observers and streams behaving like in http://reactivex.io. I am not sure this is how things work. Where did you get the idea? What you could do instead is when you press you chosen keyboard shortcut, and the method handling it gets called, you ask the text editor where the cursor position is. Then get a string a few characters back from that. Compare it with all those strings you want to replace. If you find a match, replace it and finally refresh the text editor so that the change you have made becomes visible. A lot of tedious work. Because you have to figure out what gets called when. What is stored where. What is passed where. Do some debugging. See a few 'big red Xes' or image hangs if things go wrong. Rinse and repeat. You can learn a lot about how things are connected. Are you up for the challenge? > Here are a few questions that I stumbled upon: > > SnippetExpander tries to observe whatever object has focus. > What does it mean to "have" focus? > How to know what has focus? > What does it mean to "observe"? > > When an object has focus and is the type of object you can type text in (let's > name that thing: focusedTextObject) then SnippetExpander observes its output > messages. > How to test an object and know if you can type text in it? > > When SnippetExpander observes that the ALT-TAB key has been entered, then > SnippetExpander asks the focusedTextObject the last N characters before point. > > If needed, SnippetExpander asks focusedTextObject to replace the last N > characters by a replacement string. > > Am I doing it wrong? > > Bellow, the code of SnippetExpander wrote so far that I "filedOut". The way you posted it all the leading whitespace is lost. You could try zipping it first, that way it would stay the way you filed it out with all that leading whitespace (and the weird CR line endings that Squeak uses) intact. > Thx! Best Regards, Milan Vavra |
Free forum by Nabble | Edit this page |