资讯动态

Textual TextArea 多行文本编辑器完整指南:语法高亮、主题定制与代码编辑实战

发布时间:2026/9/19 12:43:49 来源:尧图企业网站定制
Textual TextArea 多行文本编辑器完整指南语法高亮、主题定制与代码编辑实战【免费下载链接】textualThe lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.项目地址: https://gitcode.com/gh_mirrors/te/textualTextArea 是 Textual 框架内置的多行文本编辑组件支持文本选择、软换行、基于 tree-sitter 的可选语法高亮以及丰富的按键绑定。本文以 Textual 官方文档为主体结合仓库源码与示例系统讲解 TextArea 的加载与读取、光标与选区操作、主题系统、缩进与撤销/重做、只读模式、行号控制、按键拦截扩展以及自定义语言支持帮助你在终端应用中快速构建从普通多行输入框到完整代码编辑器的各类场景。概览TextArea 是什么TextArea位于 src/textual/widgets/_text_area.py是一个可聚焦、非容器的编辑组件用于编辑可能跨越多行的文本。可聚焦Focusable是容器Container否版本说明TextArea在 0.38.0 版本中加入软换行soft wrapping在 0.48.0 版本中加入。默认情况下TextArea是一个启用了软换行的标准多行输入框。它天然支持文本选择、软换行、可选的语法高亮以及一系列键位绑定足以应对大部分文本编辑需求。代码编辑 vs 纯文本编辑如果你感兴趣的是编辑代码可以直接使用TextArea.code_editor便捷构造函数。从源码可以看到它默认返回一个新的TextArea并带有如下差异化的配置软换行关闭soft_wrapFalse行号开启show_line_numbersTrueTab 键行为设置为插入\ttab_behaviorindent主题默认为monokai默认max_checkpoints50、highlight_cursor_lineTrue。一个典型的用法示例如下对应示例文件 docs/examples/widgets/text_area_example.pyfrom textual.app import App, ComposeResult from textual.widgets import TextArea TEXT \ def hello(name): print(hello name) def goodbye(name): print(goodbye name) class TextAreaExample(App): def compose(self) - ComposeResult: yield TextArea.code_editor(TEXT, languagepython) app TextAreaExample() if __name__ __main__: app.run()语法高亮依赖要启用语法高亮需要安装syntax额外依赖 pipbash pip install textual[syntax] poetrybash poetry add textual[syntax] 这会安装tree-sitter与tree-sitter-languages两个包。这两个包以二进制 wheel 形式分发因此如果你的应用运行环境中没有对应的 wheel可能会受到限制。安装完成后设置language响应式属性即可开启高亮# Set the language to Markdown text_area.language markdown加载与读取文本内容加载初始文本在compose中直接传入文本字符串即可完成初始加载见上文示例。需要程序化更新内容时直接给text属性赋字符串值text_area.text new content从 TextArea 读取内容有几种方式可以取回TextArea中的内容TextArea.text属性返回文本区域内的全部内容字符串。TextArea.selected_text属性返回当前选中区域对应的文本。TextArea.get_text_range方法返回两个位置之间的文本。无论哪种方式当取回的内容跨越多行时都会使用文档的行分隔符见下文“行分隔符”一节。编辑内容TextArea的内容可以通过replace方法更新该方法等价于“先选中一段文本再粘贴”的程序化操作。此外还提供了一些便捷方法insert在指定位置插入文本delete删除指定范围的文本clear清空全部内容。小技巧TextArea.document.end属性返回文档末尾的位置在程序化编辑时非常方便。光标与选区操作移动光标光标位置通过cursor_location属性获取它是一个(row_index, column_index)元组两个索引均从 0 开始表示光标在内容中的位置。给cursor_location赋新值会立即更新光标位置 text_area TextArea() text_area.cursor_location (0, 0) text_area.cursor_location (0, 4) text_area.cursor_location (0, 4)cursor_location是程序化移动光标的简单方式但它不能帮我们选中文本。选中文本要选中文本可以使用selection响应式属性。下面的示例选中文档的前两行对应示例 docs/examples/widgets/text_area_selection.pyfrom textual.app import App, ComposeResult from textual.widgets import TextArea from textual.widgets.text_area import Selection TEXT \ def hello(name): print(hello name) def goodbye(name): print(goodbye name) class TextAreaSelection(App): def compose(self) - ComposeResult: text_area TextArea.code_editor(TEXT, languagepython) text_area.selection Selection(start(0, 0), end(2, 0)) # (1)! yield text_area app TextAreaSelection() if __name__ __main__: app.run()选中前两行文本。注意选区可以发生在两个方向因此Selection((2, 0), (0, 0))同样是合法的。小技巧selection.end属性始终等于TextArea.cursor_location。换句话说cursor_location只是访问text_area.selection.end的一个便捷入口。更多光标工具位置信息TextArea上存在大量以cursor_at_开头、返回布尔值的属性用来描述光标当前所在位置。例如cursor_at_start_of_line告诉我们光标是否位于行首。我们还可以检查“如果移动光标光标会到达的位置”。例如get_cursor_right_location返回光标向右移动一步后会到达的位置。这类方法还有很多命名模式为get_cursor_*_location。光标移动方法move_cursor方法允许将光标移动到新位置同时可以选择文本也可以边移动边滚动以保持光标居中# Move the cursor from its current location to row index 4, # column index 8, while selecting all the text between. text_area.move_cursor((4, 8), selectTrue)move_cursor_relative提供非常相似的接口但它是相对于当前光标位置移动。常用选区以下方法可以让常见选区操作更便捷select_line按行号选中一行默认绑定 f6 键。select_all选中全部文本默认绑定 f7 键。主题系统TextArea自带若干内置主题并且很容易添加自定义主题。主题控制整体外观与风格包括语法高亮、光标、选区、行号槽gutter等。默认主题TextArea的默认主题名为css其所有取值全部来自 CSS。这意味着组件的默认外观与标准 Textual 应用浑然一体在深色和浅色模式下都表现正常。使用css主题时可以通过组件类来为TextArea的各元素设置样式。例如 CSS 代码TextArea .text-area--cursor { background: green; }会让光标变成绿色。而像代码编辑器这类更复杂的应用可能更希望使用预定义主题如monokai这需要用到TextAreaTheme对象我们会在下面详细介绍。它允许在代码层面完全自定义TextArea包括语法高亮。使用内置主题TextArea的初始主题由theme参数决定# Create a TextArea with the dracula theme. yield TextArea.code_editor(print(123), languagepython, themedracula)可以使用available_themes属性查看可用的主题 text_area TextArea() print(text_area.available_themes) {css, dracula, github_light, monokai, vscode_dark}创建TextArea之后可以通过设置theme属性在可用主题间切换text_area.theme vscode_dark设置该属性后TextArea会立即刷新并显示更新后的主题。自定义主题注意自定义主题仅对想要定制语法高亮的用户有意义。如果只是编辑纯文本、想给TextArea的某些元素重新着色应该使用组件类即上面提到的.text-area--*系列。使用自定义非内置主题分两步创建TextAreaTheme实例使用TextArea.register_theme注册它。第一步创建主题下面创建一个名为my_cool_theme的简单主题光标为蓝底白字、光标行为黄色背景并将字符串高亮为红色、注释高亮为品红色from rich.style import Style from textual.widgets.text_area import TextAreaTheme my_theme TextAreaTheme( # This name will be used to refer to the theme... namemy_cool_theme, # Basic styles such as background, cursor, selection, gutter, etc... cursor_styleStyle(colorwhite, bgcolorblue), cursor_line_styleStyle(bgcoloryellow), # syntax_styles is for syntax highlighting. # It maps tokens parsed from the document to Rich styles. syntax_styles{ string: Style(colorred), comment: Style(colormagenta), } )cursor_style、cursor_line_style这类属性对组件应用的是与语言无关的通用样式。如果你不为其中某个属性提供值它将从 CSS 组件样式中取值。syntax_styles属性用于语法高亮它依赖当前使用的language。更多细节见下文“语法高亮”一节。如果你想在现有主题的基础上扩展可以通过TextAreaTheme.get_builtin_theme类方法拿到某个内置主题的引用from textual.widgets.text_area import TextAreaTheme monokai TextAreaTheme.get_builtin_theme(monokai)第二步注册主题现在把主题注册到TextArea实例上text_area.register_theme(my_theme)注册之后它就会出现在available_themes中 print(text_area.available_themes) {dracula, github_light, monokai, vscode_dark, my_cool_theme}然后就可以切换到该主题text_area.theme my_cool_theme这会立即更新TextArea的外观。完整的可运行示例见 docs/examples/widgets/text_area_custom_theme.py其中还展示了通过text_area.cursor_blink False关闭光标闪烁的细节。Tab 与 Escape 行为默认情况下按下 tab 键会把焦点移到应用中的下一个组件——这与 Textual 中其他组件的行为一致。要让 tab 插入\t字符可以把tab_behavior属性设置为字符串indent。在该模式下可以通过按下 escape 键来切换焦点。缩进按下 Tab 时插入的字符由indent_type属性控制可选值为tabs或spaces。如果indent_type spaces按下 tab 会插入最多indent_width个空格以便与下一个制表位对齐。indent_width的默认值是 4见下方“响应式属性”表格。撤销与重做TextArea提供undo和redo方法。默认情况下undo绑定 ctrlzredo绑定 ctrly。TextArea使用一种启发式策略在特定类型的编辑之后放置检查点checkpoint。当你调用undo时从现在到最近一个检查点之间的所有编辑都会被回退。你也可以手动添加检查点通过调用TextArea.history.checkpoint()实例方法实现对应EditHistory类。撤销/重做历史采用基于栈的结构栈中的每一项代表一个检查点。在内存受限的环境中你可能希望限制检查点的最大数量可以通过向TextArea构造函数传入max_checkpoints参数来实现code_editor构造函数的默认值为 50。只读模式TextArea.read_only是一个布尔响应式属性设为True时禁止用户修改TextArea中的内容。在read_onlyTrue期间你仍然可以通过程序修改内容。该模式激活时TextArea会获得-read-onlyCSS 类你可以用它为只读模式提供自定义样式。行分隔符内容加载进TextArea时会从头到尾扫描内容并记录遇到的第一个行分隔符。之后通过text属性读取内容时会统一使用这个分隔符。TextArea不支持导出包含混合行尾mixed line endings的文本。同理粘贴进TextArea的换行符也会被转换。可以通过TextArea.document.newline查看当前文档的行分隔符 text_area TextArea() text_area.document.newline \n行号左侧包含行号的槽gutter可以通过设置show_line_numbers属性为True或False来开关text_area.show_line_numbers True设置该属性会立即重绘TextArea以反映新值。你还可以通过设置line_number_start响应式属性来改变起始行号槽中最顶部的行号。该属性在源码中声明为reactive(1, initFalse)见 src/textual/widgets/_text_area.py#L498默认值为 1。扩展 TextArea有时候你可能希望继承TextArea来添加额外功能。拦截按键可以通过重写_on_key来拦截特定按键并注入自定义功能。示例自动补全括号下面扩展TextArea加入自动闭合括号并把光标移动到合适位置的功能对应示例 docs/examples/widgets/text_area_extended.pyfrom textual import events from textual.app import App, ComposeResult from textual.widgets import TextArea class ExtendedTextArea(TextArea): A subclass of TextArea with parenthesis-closing functionality. def _on_key(self, event: events.Key) - None: if event.character (: self.insert(()) self.move_cursor_relative(columns-1) event.prevent_default() class TextAreaKeyPressHook(App): def compose(self) - ComposeResult: yield ExtendedTextArea.code_editor(languagepython) app TextAreaKeyPressHook() if __name__ __main__: app.run()这段代码在按下(时拦截按键处理插入()然后把光标移到开闭括号之间。现在往TextArea里输入def hello(时括号会被自动闭合光标正好落在括号中间。进阶概念语法高亮原理TextArea内的语法高亮由名为tree-sitter的库驱动。每当TextArea中的文档被更新时内部的语法树syntax tree都会同步更新。这棵树会被频繁查询以找出与语法高亮相关的位置区间。我们为这些区间命名并最终映射到TextAreaTheme.syntax_styles中的 Rich 样式上。为说明其工作原理我们看看 Monokai 主题是如何高亮 Markdown 文件的。当language属性被设置为markdown时会使用类似下面的高亮查询为简洁已裁剪(heading_content) heading (link) link这份高亮查询把 Markdown 解析器返回的heading_content节点映射到名字heading把link节点映射到名字link。在TextAreaTheme.syntax_styles字典中我们把名字heading映射为一个 Rich 样式。以下是 Monokai 主题中的相关片段TextAreaTheme( namemonokai, base_styleStyle(color#f8f8f2, bgcolor#272822), gutter_styleStyle(color#90908a, bgcolor#272822), # ... syntax_styles{ # Colorise heading and make them bold heading: Style(color#F92672, boldTrue), # Colorise and underline link link: Style(color#66D9EF, underlineTrue), # ... }, )要弄清syntax_styles中可以映射哪些名字建议查看 Textual 仓库中现有的主题和高亮查询.scm文件。高亮查询文件位于 src/textual/tree-sitter/highlights/已内置 python、markdown、javascript、json、go、rust、bash、html、css、xml、yaml、toml、sql、regex、java 等语言。例如 python.scm 会把标识符映射为variable、type、constant等而 markdown.scm 则定义了heading、link.uri、link.label、list.marker等名字。小技巧你也可以查看活跃TextArea实例上的TextArea._highlights内容看看当前打开的文档生成了哪些高亮。添加自定义语言支持要为TextArea添加一种语言支持使用register_language方法。注册语言需要两样东西一个 tree-sitterLanguage对象包含该语言的文法一份用于语法高亮的高亮查询。示例添加 Java 支持获取Language对象最简单的途径是使用py-tree-sitter-languages包。我们可以用它拿到表示 Java 的Language对象from tree_sitter_languages import get_language java_language get_language(java)调用get_language时所用解析器的确切版本可以通过所用py-tree-sitter-languages版本中的repos.txt文件查看。该文件包含各 tree-sitter 解析器 GitHub 仓库的链接与 commit 哈希。在这些仓库中你通常可以在queries/highlights.scm找到现成的高亮查询在src/node-types.json找到可用于高亮查询的全部节点类型。由于我们要为 Java 添加支持可以从仓库中获取 Java 的高亮查询步骤如下打开py-tree-sitter-languages仓库中的repos.txt文件找到对应tree-sitter-java的链接并前往该 GitHub 仓库可能还需要定位到repos.txt中引用的特定 commit打开queries/highlights.scm查看 Java 的示例高亮查询。请务必检查仓库中的许可证确保可以自由复制。警告务必使用与当前解析器兼容的高亮查询因此访问仓库时要注意repos.txt中的 commit 哈希。现在我们有了Language和高亮查询就可以注册 Java 语言了对应示例 docs/examples/widgets/text_area_custom_language.py其查询文件为 docs/examples/widgets/java_highlights.scmfrom pathlib import Path from tree_sitter_languages import get_language from textual.app import App, ComposeResult from textual.widgets import TextArea java_language get_language(java) java_highlight_query (Path(__file__).parent / java_highlights.scm).read_text() java_code \ class HelloWorld { public static void main(String[] args) { System.out.println(Hello, World!); } } class TextAreaCustomLanguage(App): def compose(self) - ComposeResult: text_area TextArea.code_editor(textjava_code) text_area.cursor_blink False # Register the Java language and highlight query text_area.register_language(java, java_language, java_highlight_query) # Switch to Java text_area.language java yield text_area app TextAreaCustomLanguage() if __name__ __main__: app.run()运行这个应用可以看到 Java 代码被高亮。你可以自由编辑文本语法高亮会立即更新。回顾一下我们把 tree-sitter 高亮查询中的名字如heading映射到TextAreaTheme.syntax_styles字典里的 Rich 样式对象。如果在注册语言后发现有部分高亮缺失可能的原因有当前的TextAreaTheme中没有对应高亮查询中名字的映射——给syntax_styles增加一个键值对即可解决高亮查询没有给你期望高亮的模式分配名字——这时需要更新高亮查询为它分配名字。小技巧tree-sitter 高亮查询中分配的名字通常跨多种语言复用。例如string在多种语言中都被用来高亮字符串。导航与换行信息如果你在TextArea之上构建功能查看navigator和wrapped_document属性可能会很有用navigator是一个DocumentNavigator实例可以提供关于光标在文档中位置的一般信息以及执行某些操作时光标会移动到哪里。wrapped_document是一个WrappedDocument实例可以结合换行情况把文档位置转换为视觉位置还提供各种其他便捷方法与属性。这些类的详细视图超出了本文范围但请注意TextArea的很多功能都存在于它们之中深入研究它们可能是值得的。响应式属性下表列出了TextArea的主要响应式属性见 src/textual/widgets/_text_area.pyNameTypeDefaultDescriptionlanguagestr \| NoneNone用于语法高亮的语言。themestrcss使用的主题。selectionSelectionSelection()当前选区。show_line_numbersboolFalse显示或隐藏行号。line_number_startint1槽中的起始行号。indent_widthint4缩进的空格数以及 Tab 的宽度。match_cursor_bracketboolTrue是否在光标处高亮匹配的括号。cursor_blinkboolTrue组件获得焦点时光标是否闪烁。soft_wrapboolTrue是否启用软换行。read_onlyboolFalse是否启用只读模式。消息TextArea会发出以下消息TextArea.Changed文本内容发生变更时触发。TextArea.SelectionChanged选区发生变化时触发。按键绑定TextArea定义了一组丰富的默认按键绑定覆盖光标移动方向键、行首/行尾、词首/词尾、页面上下、文本选择配合 Shift 的方向键、按行/按词选择、编辑操作插入、删除、撤销/重做、剪切/复制/粘贴以及全选f7、选行f6等功能。完整的绑定表可在TextArea.BINDINGS中查看src/textual/widgets/_text_area.py。组件类TextArea定义了若干组件类用于样式化组件的各个方面例如text-area--cursor光标、text-area--cursor-line光标行、text-area--selection选区、text-area--gutter行号槽等。来自theme属性的样式优先级更高因此主题会覆盖组件类样式。完整列表见TextArea.COMPONENT_CLASSES。补充说明要移除TextArea获得焦点时的描边效果可以在 CSS 中设置border: none; padding: 0;。相关资源Input单行文本输入组件。TextAreaTheme为TextArea提供主题。DocumentNavigator指导光标移动。WrappedDocument管理文档的换行。EditHistory管理撤销栈。tree-sitter 官方文档网站以及 Python 绑定仓库、py-tree-sitter-languages仓库提供大量 tree-sitter 语言的二进制 wheel。【免费下载链接】textualThe lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.项目地址: https://gitcode.com/gh_mirrors/te/textual创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价