2016-10-16 1 views
4

Supposons que j'ai une déclaration sur plusieurs lignes comme ceci:Pharo: comment faire Cmd + d (« faire ») exécuter l'ensemble de l'instruction sur plusieurs lignes par défaut au lieu de la ligne courante

1 to: 5 do: [:i| 
    Transcript show: i. 
    Transcript cr]. 

Actuellement, lorsque je mets un curseur de texte sur une ligne (sans rien sélectionner) et que j'appuie sur Cmd + d, Pharo essaie d'exécuter la ligne en cours. Mais ce serait plus pratique pour moi si, par défaut (quand rien n'est sélectionné), Pharo exécuterait l'instruction en cours (c'est-à-dire toute cette instruction de trois lignes), pas seulement la ligne en cours. Parce que c'est un cas beaucoup plus fréquent ("Je veux exécuter toute l'instruction") que "Je veux exécuter cette ligne particulière à l'intérieur d'une instruction" (qui dans la plupart des cas n'a pas de sens syntaxiquement, comme première et troisième lignes ici). Et dans ces occasions arrières (quand j'ai besoin d'exécuter une ligne dans une déclaration) je présélectionnerais cette ligne manuellement.

Comment puis-je y parvenir?

+0

Salut Grigory, pour moi, il est souvent logique d'exécuter la ligne en cours. Par exemple, lors de l'exécution de l'exécution dans le débogueur, j'inspecte souvent la ligne avant de faire un pas. Et pour cela, il est utile de ne pas sélectionner la ligne manuellement. Ou si vous avez un script plus long, et que vous voulez exécuter et inspecter cette ligne par ligne. –

+0

@NicolaiHess Je suis d'accord. Notez cependant que l'algorithme que j'ai esquissé dans [ma réponse] (http://stackoverflow.com/a/40071982/4081336) commencera avec la ligne courante et ajoutera seulement plus de lignes si la ligne courante ne compile pas. –

Répondre

1

Pour répondre à votre question: Jetez un coup d'œil au composant de texte. Il a une méthode pour évaluer-sélection-et-faire. Et si rien n'est sélectionné, il essaie de sélectionner la ligne en cours. Vous pouvez modifier cette implémentation pour trouver la plus grande "portée" de l'instruction. Cela pourrait être possible si vous travaillez avec le code AST au lieu du texte. J'ai travaillé une fois avec ceci, pour le rendre plus intelligent pour les expressions de code dans les commentaires (cela ne fonctionnait pas pour toutes les situations car le contexte pour obtenir la méthode AST n'est pas toujours le même pour ce composant texte)./workspace/et autre))

0

Voici l'idée d'un algorithme. Vous devrez l'améliorer et le compléter.

Définissez une classe ExpressionFinder pour trouver l'expression appropriée dans votre texte.

Dans mon sketch cette classe a les Ivars suivantes

  • string: la chaîne complète dans le volet (aire de jeux/transcription/whatever)
  • compiler: le compilateur utilisé par votre fenêtre pour évaluer le texte
  • lines: la collection d'associations pos->line, où pos est la position du line à l'intérieur de string
  • index: indice de courant à la collection lines utilisée par l'algorithme
  • interval: l'intervalle de sortie le cas échéant, sinon nil

Supposons que vous avez la string, la compiler et la position actuelle du curseur au string. Effectuez les opérations suivantes:

string: aString position: anInteger compiler: aCompiler 
    string := aString. 
    compiler := aCompiler. 
    self computeLines. 
    index := lines findLast: [:assoc | assoc key <= anInteger] 

Voici comment vous calculer la collection de lignes:

computeLines 
    | reader | 
    lines := OrderedCollection new. 
    reader := string readStream. 
    [reader atEnd] 
    whileFalse: [lines add: reader position + 1 -> reader nextLine] 

Avec tout cela, vous avez tout ce dont vous avez besoin pour trouver le fragment approprié.Voici une idée simple (que vous devez améliorer):

Commencez à l'index de ligne en cours et recherchez le fragment en ajoutant une ligne à la fois. Si trouvé, fin. Si ce n'est pas le cas, diminuez l'index et réessayez à partir de la ligne ci-dessus.

Voici le code

find 
    | i | 
    i := index. 
    [ 
    i <= 0 ifTrue: [^self]. 
    assoc := lines at: i. 
    self findFrom: assoc key] 
    whileFalse: [i := i - 1] 

findFrom: start 
    | i end success | 
    i := index. 
    [| assoc fragment | 
    assoc := lines at: i + 1 ifAbsent: [string size + 1 -> nil]. 
    end := assoc key - 1. 
    fragment := string copyFrom: start to: end. 
    success := self canCompile: fragment. 
    success not and: [end < string size]] 
    whileTrue: [i := i + 1]. 
    success ifTrue: [interval := start to: end]. 
    ^success 

Le code canCompile: fragment dépend du dialecte, sur les lignes de

canCompile: fragment 
    ^(compiler compileExpression: fragment) notNil 

Si vos signaux de compilateur CompilationErrors, vous devrez mettre un gestionnaire au canCompile: pour les éviter. Aussi, vous pourriez profiter de ces erreurs. Par exemple, si l'erreur de compilation fait référence à une variable non déclarée, vous savez que vous ne trouverez pas sa définition dans les lignes ci-dessous, donc vous devriez quitter la boucle en findFrom: afin d'essayer avec la ligne ci-dessus et ainsi de suite.