1017 !DoWhatIMeanSupport class methodsFor:'typing distance'! |
1017 !DoWhatIMeanSupport class methodsFor:'typing distance'! |
1018 |
1018 |
1019 isKey:k1 nextTo:k2 |
1019 isKey:k1 nextTo:k2 |
1020 "return true, if k1 and k2 are adjacent keys on the keyboard. |
1020 "return true, if k1 and k2 are adjacent keys on the keyboard. |
1021 This is used to specially priorize plausible typing errors of adjacent keys. |
1021 This is used to specially priorize plausible typing errors of adjacent keys. |
1022 CAVEAT: hard coded us- and german keyboards here." |
1022 CAVEAT: hard coded us-, german and french keyboards here; data should come from somewhere else." |
1023 |
1023 |
1024 ^ self isKey:k1 nextTo:k2 onKeyboard:(self keyboard) |
1024 ^ self isKey:k1 nextTo:k2 onKeyboard:(self keyboard) |
1025 |
1025 |
1026 " |
1026 " |
1027 self isKey:$a nextTo:$a |
1027 self isKey:$a nextTo:$a |
1052 self isKey:$a nextTo:$x |
1052 self isKey:$a nextTo:$x |
1053 " |
1053 " |
1054 ! |
1054 ! |
1055 |
1055 |
1056 keyboard |
1056 keyboard |
1057 "the keyboard layout (useful to figure out which keys are nearby a key, |
1057 "the keyboard layout |
1058 to find possible typing errors)" |
1058 (useful to figure out which keys are nearby a key, to find possible typing errors) |
|
1059 CAVEAT: hard coded us-, german and french keyboards here; data should come from somewhere else." |
1059 |
1060 |
1060 |lang| |
1061 |lang| |
1061 |
1062 |
1062 lang := UserPreferences current language. |
1063 lang := UserPreferences current language. |
1063 lang == #de ifTrue:[ |
1064 lang == #de ifTrue:[ |
1064 ^ #( |
1065 ^ #( |
1065 '1234567890-' |
1066 '1234567890-' |
1066 '*qwertzuiop' |
1067 '*qwertzuiop' |
1067 '**asdfghjkl:' |
1068 '**asdfghjkl:' |
1068 '***yxcvbnm' ). |
1069 '***yxcvbnm' |
|
1070 ). |
1069 ]. |
1071 ]. |
1070 |
1072 |
1071 lang == #fr ifTrue:[ |
1073 lang == #fr ifTrue:[ |
1072 ^ #( |
1074 ^ #( |
1073 '1234567890' |
1075 '1234567890' |
1074 '*azertyuiop' |
1076 '*azertyuiop' |
1075 '**qsdfghjklm' |
1077 '**qsdfghjklm' |
1076 '***wxcvbn,' ). |
1078 '***wxcvbn,' |
|
1079 ). |
1077 ]. |
1080 ]. |
1078 |
1081 |
1079 ^ #( |
1082 ^ #( |
1080 '1234567890-' |
1083 '1234567890-' |
1081 '*qwertyuiop' |
1084 '*qwertyuiop' |
1082 '**asdfghjkl:' |
1085 '**asdfghjkl:' |
1083 '***zxcvbnm' ). |
1086 '***zxcvbnm' |
|
1087 ). |
1084 |
1088 |
1085 " |
1089 " |
1086 self keyboard |
1090 self keyboard |
1087 " |
1091 " |
1088 |
1092 |
1162 "/ otherwise, a unary message is probably intended to be sent to the variable. |
1166 "/ otherwise, a unary message is probably intended to be sent to the variable. |
1163 "/ (however, no character is available to determine what is useful) |
1167 "/ (however, no character is available to determine what is useful) |
1164 forceNewMessageSend := true. |
1168 forceNewMessageSend := true. |
1165 ]. |
1169 ]. |
1166 ] ifFalse:[ |
1170 ] ifFalse:[ |
1167 (node isUnary) ifTrue:[ |
1171 (node isMessage and:[node isUnary]) ifTrue:[ |
1168 "/ expanding <rcvr> foo |<- cursor here (i.e. a space after foo) |
1172 "/ expanding <rcvr> foo |<- cursor here (i.e. a space after foo) |
1169 "/ |
1173 "/ |
1170 forceNewMessageSend := true. |
1174 forceNewMessageSend := true. |
1171 "/ "/ can we see what we get from foo? |
1175 "/ "/ can we see what we get from foo? |
1172 "/ classOfReceiver := self |
1176 "/ classOfReceiver := self |
1650 codeCompletionForMessage:node into:actionBlock |
1654 codeCompletionForMessage:node into:actionBlock |
1651 |selector srchClass implClass |
1655 |selector srchClass implClass |
1652 bestSelectors selector2 bestSelectors2 allBest best info numArgs |
1656 bestSelectors selector2 bestSelectors2 allBest best info numArgs |
1653 newParts nSelParts oldLen newLen selectorParts |
1657 newParts nSelParts oldLen newLen selectorParts |
1654 findBest parentNode selectorsSentInCode split editAction parentNodeClassIfKnown |
1658 findBest parentNode selectorsSentInCode split editAction parentNodeClassIfKnown |
1655 otherMessagesToReceiver possibleClasses receiverNodeClassIfKnown| |
1659 otherMessagesToReceiver assignmentsToReceiver possibleClasses receiverNodeClassIfKnown| |
1656 |
1660 |
1657 "/ Transcript show:'msg in '; show:methodOrNil; show:' / '; showCR:classOrNil. |
1661 "/ Transcript show:'msg in '; show:methodOrNil; show:' / '; showCR:classOrNil. |
1658 |
1662 |
1659 "/ classOrNil notNil ifTrue:[ |
1663 "/ classOrNil notNil ifTrue:[ |
1660 "/ parser := Parser parseMethod:codeView contents string in:classOrNil ignoreErrors:true ignoreWarnings:true. |
1664 "/ parser := Parser parseMethod:codeView contents string in:classOrNil ignoreErrors:true ignoreWarnings:true. |
1687 ]. |
1691 ]. |
1688 ]. |
1692 ]. |
1689 |
1693 |
1690 bestSelectors := findBest value:node receiver value:selector. |
1694 bestSelectors := findBest value:node receiver value:selector. |
1691 |
1695 |
1692 "/ if the receiver is a variable, we can look for other messages being sent to that variable in the current method |
1696 "/ if the receiver is a variable, |
|
1697 "/ we can look for other messages being sent to that variable in the current method. |
|
1698 "/ also, if there is an assignment like class new to it... |
1693 (tree notNil and:[ node receiver isVariable ]) |
1699 (tree notNil and:[ node receiver isVariable ]) |
1694 ifTrue:[ |
1700 ifTrue:[ |
1695 otherMessagesToReceiver := tree allMessageNodes |
1701 assignmentsToReceiver := tree allAssignmentNodes |
1696 select:[:eachMessageNode | |
1702 collect:[:eachAssignmentNode | |
1697 node receiver = eachMessageNode receiver |
1703 |cls| |
1698 and:[ selector ~= eachMessageNode selector]] |
1704 |
1699 thenCollect:[:eachNode | eachNode selector]. |
1705 (node receiver = eachAssignmentNode variable |
1700 possibleClasses := Smalltalk allClassesForWhich:[:cls | |
1706 and:[ (cls := self classOfNode:eachAssignmentNode value) notNil ] |
1701 otherMessagesToReceiver conform:[:eachSelectorSent | cls canUnderstand:eachSelectorSent]]. |
1707 ) ifTrue:[ |
1702 possibleClasses := possibleClasses select:[:cls | cls isLoaded]. |
1708 cls |
|
1709 ] ifFalse:[ |
|
1710 nil |
|
1711 ] |
|
1712 ] |
|
1713 thenSelect:[:classOrNil | classOrNil notNil]. |
|
1714 assignmentsToReceiver notEmptyOrNil ifTrue:[ |
|
1715 possibleClasses := assignmentsToReceiver |
|
1716 ] ifFalse:[ |
|
1717 otherMessagesToReceiver := tree allMessageNodes |
|
1718 select:[:eachMessageNode | |
|
1719 node receiver = eachMessageNode receiver |
|
1720 and:[ selector ~= eachMessageNode selector]] |
|
1721 thenCollect:[:eachNode | eachNode selector]. |
|
1722 otherMessagesToReceiver := otherMessagesToReceiver asSet. |
|
1723 possibleClasses := Smalltalk allClassesForWhich:[:cls | |
|
1724 otherMessagesToReceiver conform:[:eachSelectorSent | cls includesSelector: "canUnderstand:" eachSelectorSent]]. |
|
1725 possibleClasses := possibleClasses select:[:cls | cls isLoaded]. |
|
1726 ]. |
1703 (possibleClasses notEmpty and:[possibleClasses size < 10]) ifTrue:[ |
1727 (possibleClasses notEmpty and:[possibleClasses size < 10]) ifTrue:[ |
1704 bestSelectors := Set new. |
1728 bestSelectors := Set new. |
1705 possibleClasses do:[:eachClass | |
1729 possibleClasses do:[:eachClass | |
1706 |bestSelectorsForClass| |
1730 |bestSelectorsForClass| |
1707 |
1731 |
1905 self information:info. |
1929 self information:info. |
1906 ]. |
1930 ]. |
1907 |
1931 |
1908 editAction := |
1932 editAction := |
1909 [:index | |
1933 [:index | |
1910 |best| |
1934 |chosen| |
1911 |
1935 |
1912 best := allBest at:index. |
1936 chosen := allBest at:index. |
1913 |
1937 |
1914 best ~= selector ifTrue:[ |
1938 chosen ~= selector ifTrue:[ |
1915 numArgs := best numArgs. |
1939 numArgs := chosen numArgs. |
1916 (bestSelectors2 notEmptyOrNil and:[bestSelectors2 includes:best]) ifTrue:[ |
1940 (bestSelectors2 notEmptyOrNil and:[bestSelectors2 includes:chosen]) ifTrue:[ |
1917 selectorParts := parentNode selectorParts , node selectorParts. |
1941 selectorParts := parentNode selectorParts , node selectorParts. |
1918 ] ifFalse:[ |
1942 ] ifFalse:[ |
1919 selectorParts := node selectorParts. |
1943 selectorParts := node selectorParts. |
1920 ]. |
1944 ]. |
1921 nSelParts := selectorParts size. |
1945 nSelParts := selectorParts size. |
1922 |
1946 |
1923 newParts := best asCollectionOfSubstringsSeparatedBy:$:. |
1947 newParts := chosen asCollectionOfSubstringsSeparatedBy:$:. |
1924 newParts := newParts select:[:part | part size > 0]. |
1948 newParts := newParts select:[:part | part size > 0]. |
1925 |
1949 |
1926 codeView |
1950 codeView |
1927 undoableDo:[ |
1951 undoableDo:[ |
1928 |newCursorPosition stop checkForArgumentTemplates| |
1952 |newCursorPosition stop checkForArgumentTemplates| |
1929 |
1953 |
1930 checkForArgumentTemplates := false. |
1954 checkForArgumentTemplates := false. |
1931 (selector isUnarySelector and:[best isKeywordSelector]) ifTrue:[ checkForArgumentTemplates := true ]. |
1955 (selector isUnarySelector and:[chosen isKeywordSelector]) ifTrue:[ checkForArgumentTemplates := true ]. |
1932 numArgs > nSelParts ifTrue:[ |
1956 numArgs > nSelParts ifTrue:[ |
1933 "/ new selector has more arguments; append them |
1957 "/ new selector has more arguments; append them |
1934 stop := selectorParts last stop. |
1958 stop := selectorParts last stop. |
1935 |
1959 |
1936 "/ append the rest ... |
1960 "/ append the rest ... |
1937 numArgs downTo:nSelParts+1 do:[:idx | |
1961 numArgs downTo:nSelParts+1 do:[:idx | |
1938 |newPart| |
1962 |newPart| |
1939 |
1963 |
1940 newPart := newParts at:idx. |
1964 newPart := newParts at:idx. |
1941 (best endsWith:$:) ifTrue:[ |
1965 (chosen endsWith:$:) ifTrue:[ |
1942 newPart := newPart , ':' |
1966 newPart := newPart , ':' |
1943 ]. |
1967 ]. |
1944 |
1968 |
1945 (codeView characterAtCharacterPosition:stop) == $: ifFalse:[ |
1969 (codeView characterAtCharacterPosition:stop) == $: ifFalse:[ |
1946 newPart := ':' , newPart. |
1970 newPart := ':' , newPart. |
1960 newPart := newParts at:idx. |
1984 newPart := newParts at:idx. |
1961 oldPartialToken := selectorParts at:idx. |
1985 oldPartialToken := selectorParts at:idx. |
1962 start := oldPartialToken start. |
1986 start := oldPartialToken start. |
1963 stop := oldPartialToken stop. |
1987 stop := oldPartialToken stop. |
1964 |
1988 |
1965 (best endsWith:$:) ifTrue:[ |
1989 (chosen endsWith:$:) ifTrue:[ |
1966 (codeView characterAtCharacterPosition:stop+1) == $: ifFalse:[ |
1990 (codeView characterAtCharacterPosition:stop+1) == $: ifFalse:[ |
1967 newPart := newPart , ':' |
1991 newPart := newPart , ':' |
1968 ] |
1992 ] |
1969 ] ifFalse:[ |
1993 ] ifFalse:[ |
1970 (codeView characterAtCharacterPosition:stop) == $: ifTrue:[ |
1994 (codeView characterAtCharacterPosition:stop) == $: ifTrue:[ |
1998 extra := hasSpace ifTrue:[''] ifFalse:[' ']. |
2022 extra := hasSpace ifTrue:[''] ifFalse:[' ']. |
1999 |
2023 |
2000 ( |
2024 ( |
2001 #( |
2025 #( |
2002 'ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:' 'and:' 'or:' |
2026 'ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:' 'and:' 'or:' |
2003 ) includes:best |
2027 ) includes:chosen |
2004 ) ifTrue:[ |
2028 ) ifTrue:[ |
2005 codeView insertStringAtCursor:('[]',extra). |
2029 codeView insertStringAtCursor:('[]',extra). |
2006 codeView cursorLeft:1+extra size. |
2030 codeView cursorLeft:1+extra size. |
2007 ]. |
2031 ]. |
2008 ( |
2032 ( |
2009 #( |
2033 #( |
2010 'collect:' 'select:' 'reject:' 'do:' |
2034 'collect:' 'select:' 'reject:' 'do:' |
2011 ) includes:best |
2035 ) includes:chosen |
2012 ) ifTrue:[ |
2036 ) ifTrue:[ |
2013 codeView insertStringAtCursor:('[:each | ]',extra). |
2037 codeView insertStringAtCursor:('[:each | ]',extra). |
2014 codeView cursorLeft:1+extra size. |
2038 codeView cursorLeft:1+extra size. |
2015 ]. |
2039 ]. |
2016 ]. |
2040 ]. |
2035 [:suggestions :action :whatIsIt | |
2059 [:suggestions :action :whatIsIt | |
2036 |
2060 |
2037 |chosen| |
2061 |chosen| |
2038 |
2062 |
2039 chosen := self askUserForCompletion:whatIsIt for:codeView at:node start from:suggestions. |
2063 chosen := self askUserForCompletion:whatIsIt for:codeView at:node start from:suggestions. |
2040 action value:(suggestions indexOf:chosen) |
2064 chosen notNil ifTrue:[ |
|
2065 action value:(suggestions indexOf:chosen) |
|
2066 ]. |
2041 ]. |
2067 ]. |
2042 |
2068 |
2043 "/ |crsrPos |
2069 "/ |crsrPos |
2044 "/ selectorSoFar matchingSelectors |
2070 "/ selectorSoFar matchingSelectors |
2045 "/ selectors distances best rest |
2071 "/ selectors distances best rest |