Smalltalk Pharo:如何让Cmd+d(“DoIt”)在默认情况下执行整个多行语句,而不仅仅是当前行

Smalltalk Pharo:如何让Cmd+d(“DoIt”)在默认情况下执行整个多行语句,而不仅仅是当前行,smalltalk,pharo,Smalltalk,Pharo,假设我有这样一个多行语句: 1 to: 5 do: [:i| Transcript show: i. Transcript cr]. 当前,当我将文本光标放在某行上而不选择任何内容并按Cmd+d时,Pharo会尝试执行当前行。但如果默认情况下,当未选择任何内容时,Pharo将执行当前语句,即所有这三行语句,而不仅仅是当前行,则对我来说会更方便。因为这是一种更常见的情况,我想执行整个语句,而不是在语句中执行这一行,在大多数情况下,这一行在语法上没有意义,这里是第一行和第三行。在这种情况下

假设我有这样一个多行语句:

1 to: 5 do: [:i|
  Transcript show: i.
  Transcript cr].
当前,当我将文本光标放在某行上而不选择任何内容并按Cmd+d时,Pharo会尝试执行当前行。但如果默认情况下,当未选择任何内容时,Pharo将执行当前语句,即所有这三行语句,而不仅仅是当前行,则对我来说会更方便。因为这是一种更常见的情况,我想执行整个语句,而不是在语句中执行这一行,在大多数情况下,这一行在语法上没有意义,这里是第一行和第三行。在这种情况下,当我需要在语句中执行一行时,我会手动预选这一行


如何实现这一点?

回答您的问题:看一下文本组件。它有一些评估选择和执行的方法。如果未选择任何内容,则尝试选择当前行。 您可以更改此实现以查找最顶层的语句范围。
如果您使用代码AST而不是文本,这是可能的。我曾经使用过它,以使注释中的代码表达式更智能。这并不适用于所有情况,因为对于这个文本组件,获取方法AST的上下文并不总是相同的,在不同的工具浏览器/工作区/和其他

这里是算法的想法。你需要改进并完成它

定义一个类ExpressionFinder,用于在文本中查找正确的表达式

在我的素描中,这门课有以下几个IVAR

字符串: 窗格中的完整字符串操场/成绩单/任何内容 编译器: 窗格用于计算文本的编译器 行:关联pos->line的集合,其中pos是行在字符串中的位置 索引:算法使用的行集合的当前索引 间隔:输出间隔(如果有),否则为零 假设您得到了字符串、编译器和光标在字符串上的当前位置。请执行以下操作:

string: aString position: anInteger compiler: aCompiler
  string := aString.
  compiler := aCompiler.
  self computeLines.
  index := lines findLast: [:assoc | assoc key <= anInteger]
有了这些,你就有了找到合适片段所需的一切。以下是一个您应该改进的简单想法:

从当前行索引开始,通过一次添加一行来查找片段。如果找到,结束。如果没有,请减少索引,然后从上一行重试

这是密码

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

如果编译器发出编译错误信号,则需要在canCompile:中放置一个处理程序以避免它们。您还可以利用这些错误。例如,如果编译错误引用了一个未声明的变量,那么您知道在下面的行中找不到它的定义,因此您应该在findFrom:so中退出循环以尝试上面的行,依此类推。

Hi Grigory,对我来说,只执行当前行通常是有意义的。例如,在调试器中单步执行时,我经常在执行步骤之前检查该行。因此,不手动选择线是很有用的。或者如果您有一个较长的脚本,并且希望逐行执行和检查该脚本。@NicolaiHess我同意。但是请注意,我在中绘制的算法将从当前行开始,并且仅在当前行未编译时添加更多行。
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
canCompile: fragment
  ^(compiler compileExpression: fragment) notNil