Racket 中的基本代码编辑器功能
Basic code editor functionality in Racket
我正在创建一个用于实时编码性能的程序,为此我需要一个基本的 S 表达式代码编辑器(我输入的内容将 eval
在适当的语法上下文中编辑为 Racket 代码) .
由于 DrRacket 本身是用 Racket 编写的,我希望重新创建其代码编辑器的文本编辑功能会相当轻松,并且会记录在案,但我没有找到任何指导。到目前为止我有以下代码:
(define frame (new frame% [label "Simple Edit"]
[width 800]
[height 800]))
(define canvas (new editor-canvas% [parent frame]))
(define text (new text%))
(send canvas set-editor text)
(send frame show #t)
(define menu-bar (new menu-bar% [parent frame]))
(define edit-menu (new menu% [label "Edit"] [parent menu-bar]))
(define execution-menu (new menu% [label "Execution"] [parent menu-bar]))
(new menu-item% [label "Run"]
[parent execution-menu]
[callback (λ (mi e) (update (send text get-text)))]
[shortcut #\R]
[shortcut-prefix '(cmd)])
(append-editor-operation-menu-items edit-menu #f)
(define delta (make-object style-delta% 'change-size 14))
(send delta set-face "Menlo")
(send text change-style delta)
有了这个我就把字体和大小设置成了一个合适的,复制粘贴等操作都可以了。但是有很多意想不到的行为,例如:
- 按修饰符+字母组合键仍然会插入字母而不是忽略它。
- 按 alt+left 或 cmd+left(Mac 用户)会将插入符号移动一个字符而不是一个单词或移动到页边距。
- 双击不会select一个字。
我不想重新发明轮子,所以我用谷歌搜索但无济于事,尝试查看 DrRacket 源代码(对于我对语言的理解仍然有限,它太复杂了)等。没有这似乎不是关于使用 GUI 工具包本身的一个很好的解释(这不仅仅是参考),而且我上面粘贴的内容让我进行了大量的反复试验,所以我不期待手动实现所有这些基本的文本编辑功能。
如果有人有一个项目源代码来举例说明如何完成这项工作,一些解决了它的包,或者一些可以让我走上正轨的指针,我将不胜感激!
DrRacket 大量使用了 framework
library, which is a higher level toolkit of GUI components built on top of racket/gui
. The editor component interface that supports syntax highlighting is color:text<%>
, which supports fairly advanced, completely customizable syntax highlighting based on an arbitrary lexing function you provide to the start-colorer
method. The color:text<%>
interface is itself based on top of text:basic<%>
,它也来自 framework
并实现了您描述的一些非着色相关的编辑行为。
由于color:text<%>
是一个接口,不能直接使用,但是framework
也提供了color:text%
, a concrete implementation that can be created and manipulated like any other component. If you need more flexibility, there’s also color:text-mixin
, which allows adding color:text<%>
functionality to arbitrary text editor classes. There exist parallels for text:basic<%>
in the form of text:basic%
and text:basic-mixin
.
framework
的源代码是 the gui-lib
package, available on GitHub here 的一部分。您还可以在 DrRacket 中浏览源代码而无需克隆任何东西——只需右键单击模块名称并选择 Open main.rkt 或类似的,或使用 File → Open Require Path... 菜单选项并输入已安装模块的路径以打开其源代码。
为了更好地了解如何使用 color:text<%>
的语法着色功能,查看 syntax-color/default-lexer
for a very simple lexer that implements the required protocol or syntax-color/racket-lexer
DrRacket 实际使用的更复杂的词法分析器可能也很有用高亮球拍代码。
最后,还值得注意的是,所有这些实际上都可以通过使用 #lang
机制 在 DrRacket 本身 中自定义,因此自定义 #lang
s实际上可以提供他们自己的词法分析器,DrRacket 将使用这些分析器。这显然需要最少的重新发明轮子,但听起来您想完全实现自己的编辑器,在这种情况下,使用 framework
中的组件将是您最好的选择。
编辑部分(不是 "run" 部分)的功能由 framework
库中的 racket:text%
class 提供。
#lang racket/gui
(require framework)
(define frame
(new frame% [label "Simple Editor"] [width 800] [height 800]))
(define text-editor
(new racket:text%))
(define canvas
(new editor-canvas% [parent frame] [editor text-editor]))
(send frame show #true)
这会处理语法突出显示、paren 匹配、双击 s-expression 和缩进。您在问题中的代码是添加 "run" 功能的开始,因为回调函数可以在应该是 运行 时获取文本。所以现在你所需要的只是一个函数,它可以接受一段文本并 运行 它。为此,您可以使用 racket/sandbox
中的 make-module-evaluator
。
(require racket/sandbox)
(define (run-text str)
(define repl-ev
(parameterize ([sandbox-output (current-output-port)]
[sandbox-error-output (current-error-port)])
(make-module-evaluator str)))
(void))
然后你可以在你的回调函数中使用 run-text
像这样:
[callback (λ (mi e) (run-text (send text-editor get-text)))]
按照目前的设置方式,运行启用模块会在 DrRacket 的交互中打印结果 window。为此,您可能需要自己的互动 window,但我不确定该怎么做。
语言racket/gui
(需要框架)
(要求(仅在 mzlib/string 从字符串中读取所有 expr->string))
(定义 ns (make-base-namespace))
(eval '(需要方案) ns)
(定义框架
(新框架%[标签"Simple Editor"][宽度800][高度200]))
(定义文本编辑器
(新 racket:text%)
(定义 canvas
(new editor-canvas% [parent frame] (min-height 120)[editor text-editor]))
(发送帧显示#true)
(定义文本编辑器2
(新 racket:text%)
(定义 canvas2
(new editor-canvas% [parent frame] (min-height 120)[editor text-editor2]))
(定义hpa(新水平面板%
(parent frame)(alignment '(center center))))
(定义按钮评估
(新按钮 %(父 hpa)
(标签 "Evaluer")
(样式'(边框))
(回调 (lambda (b e) ; b=按钮, e=事件
(发送 text-editor2 擦除)
(let ((L (read-from-string-all (send text-editor get-text)))))
(for-each (lambda (expr)
(发送 text-editor2 insert (expr->string (eval expr ns)))
(发送 text-editor2 插入 "\n"))
大号))))))
我正在创建一个用于实时编码性能的程序,为此我需要一个基本的 S 表达式代码编辑器(我输入的内容将 eval
在适当的语法上下文中编辑为 Racket 代码) .
由于 DrRacket 本身是用 Racket 编写的,我希望重新创建其代码编辑器的文本编辑功能会相当轻松,并且会记录在案,但我没有找到任何指导。到目前为止我有以下代码:
(define frame (new frame% [label "Simple Edit"]
[width 800]
[height 800]))
(define canvas (new editor-canvas% [parent frame]))
(define text (new text%))
(send canvas set-editor text)
(send frame show #t)
(define menu-bar (new menu-bar% [parent frame]))
(define edit-menu (new menu% [label "Edit"] [parent menu-bar]))
(define execution-menu (new menu% [label "Execution"] [parent menu-bar]))
(new menu-item% [label "Run"]
[parent execution-menu]
[callback (λ (mi e) (update (send text get-text)))]
[shortcut #\R]
[shortcut-prefix '(cmd)])
(append-editor-operation-menu-items edit-menu #f)
(define delta (make-object style-delta% 'change-size 14))
(send delta set-face "Menlo")
(send text change-style delta)
有了这个我就把字体和大小设置成了一个合适的,复制粘贴等操作都可以了。但是有很多意想不到的行为,例如:
- 按修饰符+字母组合键仍然会插入字母而不是忽略它。
- 按 alt+left 或 cmd+left(Mac 用户)会将插入符号移动一个字符而不是一个单词或移动到页边距。
- 双击不会select一个字。
我不想重新发明轮子,所以我用谷歌搜索但无济于事,尝试查看 DrRacket 源代码(对于我对语言的理解仍然有限,它太复杂了)等。没有这似乎不是关于使用 GUI 工具包本身的一个很好的解释(这不仅仅是参考),而且我上面粘贴的内容让我进行了大量的反复试验,所以我不期待手动实现所有这些基本的文本编辑功能。
如果有人有一个项目源代码来举例说明如何完成这项工作,一些解决了它的包,或者一些可以让我走上正轨的指针,我将不胜感激!
DrRacket 大量使用了 framework
library, which is a higher level toolkit of GUI components built on top of racket/gui
. The editor component interface that supports syntax highlighting is color:text<%>
, which supports fairly advanced, completely customizable syntax highlighting based on an arbitrary lexing function you provide to the start-colorer
method. The color:text<%>
interface is itself based on top of text:basic<%>
,它也来自 framework
并实现了您描述的一些非着色相关的编辑行为。
由于color:text<%>
是一个接口,不能直接使用,但是framework
也提供了color:text%
, a concrete implementation that can be created and manipulated like any other component. If you need more flexibility, there’s also color:text-mixin
, which allows adding color:text<%>
functionality to arbitrary text editor classes. There exist parallels for text:basic<%>
in the form of text:basic%
and text:basic-mixin
.
framework
的源代码是 the gui-lib
package, available on GitHub here 的一部分。您还可以在 DrRacket 中浏览源代码而无需克隆任何东西——只需右键单击模块名称并选择 Open main.rkt 或类似的,或使用 File → Open Require Path... 菜单选项并输入已安装模块的路径以打开其源代码。
为了更好地了解如何使用 color:text<%>
的语法着色功能,查看 syntax-color/default-lexer
for a very simple lexer that implements the required protocol or syntax-color/racket-lexer
DrRacket 实际使用的更复杂的词法分析器可能也很有用高亮球拍代码。
最后,还值得注意的是,所有这些实际上都可以通过使用 #lang
机制 在 DrRacket 本身 中自定义,因此自定义 #lang
s实际上可以提供他们自己的词法分析器,DrRacket 将使用这些分析器。这显然需要最少的重新发明轮子,但听起来您想完全实现自己的编辑器,在这种情况下,使用 framework
中的组件将是您最好的选择。
编辑部分(不是 "run" 部分)的功能由 framework
库中的 racket:text%
class 提供。
#lang racket/gui
(require framework)
(define frame
(new frame% [label "Simple Editor"] [width 800] [height 800]))
(define text-editor
(new racket:text%))
(define canvas
(new editor-canvas% [parent frame] [editor text-editor]))
(send frame show #true)
这会处理语法突出显示、paren 匹配、双击 s-expression 和缩进。您在问题中的代码是添加 "run" 功能的开始,因为回调函数可以在应该是 运行 时获取文本。所以现在你所需要的只是一个函数,它可以接受一段文本并 运行 它。为此,您可以使用 racket/sandbox
中的 make-module-evaluator
。
(require racket/sandbox)
(define (run-text str)
(define repl-ev
(parameterize ([sandbox-output (current-output-port)]
[sandbox-error-output (current-error-port)])
(make-module-evaluator str)))
(void))
然后你可以在你的回调函数中使用 run-text
像这样:
[callback (λ (mi e) (run-text (send text-editor get-text)))]
按照目前的设置方式,运行启用模块会在 DrRacket 的交互中打印结果 window。为此,您可能需要自己的互动 window,但我不确定该怎么做。
语言racket/gui
(需要框架) (要求(仅在 mzlib/string 从字符串中读取所有 expr->string))
(定义 ns (make-base-namespace)) (eval '(需要方案) ns)
(定义框架 (新框架%[标签"Simple Editor"][宽度800][高度200])) (定义文本编辑器 (新 racket:text%) (定义 canvas (new editor-canvas% [parent frame] (min-height 120)[editor text-editor]))
(发送帧显示#true)
(定义文本编辑器2 (新 racket:text%) (定义 canvas2 (new editor-canvas% [parent frame] (min-height 120)[editor text-editor2]))
(定义hpa(新水平面板% (parent frame)(alignment '(center center))))
(定义按钮评估 (新按钮 %(父 hpa) (标签 "Evaluer") (样式'(边框)) (回调 (lambda (b e) ; b=按钮, e=事件 (发送 text-editor2 擦除) (let ((L (read-from-string-all (send text-editor get-text))))) (for-each (lambda (expr) (发送 text-editor2 insert (expr->string (eval expr ns))) (发送 text-editor2 插入 "\n")) 大号))))))