假设我有这样的多行语句:
1 to: 5 do: [:i|
Transcript show: i.
Transcript cr].
目前,当我将文本光标放在某行上(没有选择任何内容)并按下Cmd + d时,Pharo会尝试执行当前行。但是如果默认情况下(当没有选择任何内容时)对我来说会更方便Pharo将执行当前语句(即所有这三行语句),而不仅仅是当前行。因为这是一个更频繁的情况(“我想执行整个语句”)而不是“我想在一个语句中执行这个特定的行”(在大多数情况下,这在语法上没有意义,因为第1行和第3行这里)。在这些后方场合(当我需要在声明中执行一行时)我会手动预先选择这一行。
我怎样才能做到这一点?
答案 0 :(得分:1)
回答你的问题:看看文本组件。它有一些评估选择和做的方法。如果未选择任何内容,则会尝试选择当前行。 您可以更改此实现以查找最顶层的语句“范围”。 如果您使用代码AST而不是文本,则可能。我用这个工作了一次,使注释中的代码表达式变得更聪明。(这对所有情况都不起作用,因为在不同的工具(浏览器)中获取方法AST的上下文对于这个文本组件并不总是相同的/ workspace / and other))
答案 1 :(得分:0)
这是算法的想法。您需要改进并完善它。
定义一个类ExpressionFinder
,以便在文本中找到正确的表达式。
在我的草图中,这个类有以下ivars
string
:
窗格中的完整字符串(playground / transcript / whatever)compiler
:
窗格用于评估文本的编译器lines
:关联pos->line
的集合,其中pos
是line
内string
index
:算法使用的lines
集合的当前索引interval
:输出间隔(如果有),否则为nil
假设您在string
上获得了compiler
,position
和当前string
光标。执行以下操作:
string: aString position: anInteger compiler: aCompiler
string := aString.
compiler := aCompiler.
self computeLines.
index := lines findLast: [:assoc | assoc key <= anInteger]
以下是计算线条集合的方法:
computeLines
| reader |
lines := OrderedCollection new.
reader := string readStream.
[reader atEnd]
whileFalse: [lines add: reader position + 1 -> reader nextLine]
有了这一切,您就拥有了找到合适片段所需的一切。这是一个简单的想法(你应该改进):
从当前行索引开始,通过一次添加一行来查找片段。如果找到,结束。如果没有,请降低索引并从上面的行重试。
这是代码
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
的代码依赖于方言,在
canCompile: fragment
^(compiler compileExpression: fragment) notNil
如果编译器发出CompilationErrors
信号,则需要在canCompile:
中放置一个处理程序以避免它们。您也可以利用此类错误。例如,如果编译错误引用了未声明的变量,您知道在下面的行中找不到它的定义,因此您应该在findFrom:
中退出循环,以便尝试使用上面的行等等。