Skip to main content

A text area (multi-line input) with syntax highlighting for Textual

Project description

Textual Textarea

Textual Textarea Screenshot

Note: This is NOT the official TextArea widget!

With v0.38.0, Textual added a built-in TextArea widget. You probably want to use that widget instead of this one. In a future version, this widget will be refactored to use the official widget (and likely add some features and change some key bindings).

Installation

pip install textual-textarea

Features

Full-featured text editor experience with VS-Code-like bindings, in your Textual App:

  • Syntax highlighting and support for themes.
  • Move cursor and scroll with mouse or keys (including ctrl+arrow, PgUp/Dn, Home/End).
  • Select text using shift or click and drag.
  • Open (ctrl+o) and save (ctrl+s) files.
  • Cut (ctrl+x), copy (ctrl+c), paste (ctrl+u/v), optionally using the system clipboard.
  • Comment selections with ctrl+/.
  • Indent and dedent (optionally for a multiline selection) to tab stops with Tab and shift+Tab.
  • Automatic completions of quotes and brackets.
  • Quit with ctrl+q.

Usage

Initializing the Widget

The TextArea is a Textual Widget. You can add it to a Textual app using compose or mount:

from textual_textarea import TextArea
from textual.app import App, ComposeResult

class TextApp(App, inherit_bindings=False):
    def compose(self) -> ComposeResult:
        yield TextArea(language="python", theme="solarized-dark")

    def on_mount(self) -> None:
        ta = self.query_one(TextArea)
        ta.focus()

app = TextApp()
app.run()

In addition to the standard Widget arguments, TextArea accepts three additional, optional arguments when initializing the widget:

  • language (str): Must be None or the short name of a Pygments lexer, e.g., python, sql, as3. Defaults to None.
  • theme (str): Must be name of a Pygments style, e.g., bw, github-dark, solarized-light. Defaults to monokai.
  • use_system_clipboard (bool): Set to False to make the TextArea's copy and paste operations ignore the system clipboard. Defaults to True. Some Linux users may need to apt-install xclip or xsel to enable the system clipboard features.

The TextArea supports many actions and key bindings. For proper binding of ctrl+c to the COPY action, you must initialize your App with inherit_bindings=False (as shown above), so that ctrl+c does not quit the app. The TextArea implements ctrl+q as quit; you way wish to mimic that in your app so that other in-focus widgets use the same behavior.

Interacting with the Widget

Getting and Setting Text

The TextArea exposes a text property that contains the full text contained in the widget. You can retrieve or set the text by interacting with this property:

ta = self.query_one(TextArea)
old_text = ta.text
ta.text = "New Text!\n\nMany Lines!"

Similarly, the TextArea exposes a selected_text property (read-only):

ta = self.query_one(TextArea)
selection = ta.selected_text

Inserting Text

You can insert text at the current selection:

ta = self.query_one(TextArea)
ta.text = "01234"
ta.cursor = (0, 2)
ta.insert_text_at_selection("\nabc\n")
assert ta.text == "01\nabc\n234"
assert ta.cursor == Cursor(lno=2, pos=0)

Getting and Setting The Cursor Position

The TextArea exposes a cursor property that returns a NamedTuple with the position of the cursor. The tuple is (line_number, x_pos):

ta = self.query_one(TextArea)
old_cursor = ta.cursor
ta.cursor = (999, 0)  # the cursor will move as close to line 999, pos 0 as possible
cursor_line_number = ta.cursor.lno
cursor_x_position = ta.cursor.pos

Similarly, there is a selection_anchor property (Union[None, Cursor]):

ta = self.query_one(TextArea)
anchor = ta.selection_anchor # will be None if no text is selected
ta.selection_anchor = (999, 0)  # the anchor will move as close to line 999, pos 0 as possible
ta.selection_anchor = None # the selection will be cleared

Getting and Setting The Language

Syntax highlighting and comment insertion depends on the configured language for the TextArea.

The TextArea exposes a language property that returns None or a string that is equal to the short name of the Pygments lexer for the currently configured language:

ta = self.query_one(TextArea)
old_language = ta.language
ta.language = "python"

Getting Theme Colors

If you would like the rest of your app to match the colors from the TextArea's theme, they are exposed via the theme_colors property.

ta = self.query_one(TextArea)
color = ta.theme_colors.contrast_text_color
bgcolor = ta.theme_colors.bgcolor
highlight = ta.theme_colors.selection_bgcolor

Adding Bindings and other Behavior

You can subclass TextArea to add your own behavior. This snippet adds an action that posts a Submitted message containing the text of the TextArea when the user presses ctrl+j:

from textual.message import Message
from textual_textarea import TextArea


class CodeEditor(TextArea):
    BINDINGS = [
        ("ctrl+j", "submit", "Run Query"),
    ]

    class Submitted(Message, bubble=True):
        def __init__(self, text: str) -> None:
            super().__init__()
            self.text = text

    async def action_submit(self) -> None:
        self.post_message(self.Submitted(self.text))

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

textual_textarea-0.7.3.tar.gz (18.7 kB view hashes)

Uploaded Source

Built Distribution

textual_textarea-0.7.3-py3-none-any.whl (19.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page