Skip to content

trading_agent.terminal.screens.files_screen

The Files page: the user's editable files, with an editor, and the changes desks propose to them.

It copies the web page's FilesPage.tsx. A file opens in an editor; Ctrl+S saves it and Ctrl+U puts back the text as it was last saved. Leaving a file with unsaved changes asks first. Proposals show their diff and are accepted with a or rejected with x.

Typical usage example:

app.push_screen(FilesScreen('general'))

FilesScreen

FilesScreen(desk_name)

Bases: PageScreen

The Files page.

Creates the page.

Parameters:

Name Type Description Default
desk_name str

The desk the chat shows.

required
Source code in src/trading_agent/terminal/screens/files_screen.py
def __init__(self, desk_name: str):
    """Creates the page.

    Args:
        desk_name (str): The desk the chat shows.
    """
    super().__init__(desk_name)
    self._files: list[dict[str, Any]] = []
    self._proposals: list[dict[str, Any]] = []
    self._shown_proposals: list[dict[str, Any]] = []
    self._show_decided = False
    self._open_file: dict[str, Any] | None = None
    self._saved_text = ''
    self._open_proposal: dict[str, Any] | None = None
    self._formatter = formatter.Formatter()

compose_page

compose_page()

Builds the file and proposal lists and the editor and diff panes.

Yields:

Type Description
Widget

The page's parts.

Source code in src/trading_agent/terminal/screens/files_screen.py
def compose_page(self):
    """Builds the file and proposal lists and the editor and diff panes.

    Yields:
        Widget: The page's parts.
    """
    with containers.Horizontal(classes='page-columns'):
        with containers.Vertical(classes='page-left'):
            yield widgets.Static('[b]Files[/b]', classes='page-heading')
            yield widgets.OptionList(id='files-list')
            yield widgets.Static(
                '', id='proposals-heading', classes='page-heading'
            )
            yield widgets.OptionList(id='proposals-list')
        with containers.Vertical(classes='page-right'):
            yield widgets.Static(
                '[dim]Choose a file or a proposal on the left.[/dim]',
                id='files-right-title',
            )
            yield widgets.TextArea(
                '',
                id='files-editor',
                language='markdown',
                show_line_numbers=True,
            )
            with containers.VerticalScroll(id='files-diff-scroll'):
                yield diff_view.DiffView(id='files-diff')

on_mount

on_mount()

Hides the editor and the diff until something is chosen.

Source code in src/trading_agent/terminal/screens/files_screen.py
def on_mount(self) -> None:
    """Hides the editor and the diff until something is chosen."""
    self.query_one('#files-editor').display = False
    self.query_one('#files-diff-scroll').display = False
    super().on_mount()

refresh_page async

refresh_page()

Reads the files and the proposals.

Source code in src/trading_agent/terminal/screens/files_screen.py
@work(exclusive=True, group='page')
async def refresh_page(self) -> None:
    """Reads the files and the proposals."""
    gateway = self.app.gateway
    try:
        files = await gateway.files()
        proposals = await gateway.proposals()
    except gateway_client.GatewayError as error:
        self.problem(error.message)
        return
    self._files = files.get('files') or []
    self._proposals = proposals.get('proposals') or []
    listing = self.query_one('#files-list', widgets.OptionList)
    listing.clear_options()
    for file in self._files:
        where = file.get('desk') or 'shared'
        size = f'{file.get("characters", 0)} characters'
        if not file.get('exists'):
            size = 'not created yet'
        listing.add_option(
            option_list.Option(
                Content.from_markup(
                    '$name [dim]$where · $size[/dim]',
                    name=str(file.get('name', '')),
                    where=where,
                    size=size,
                )
            )
        )
    if self._files and listing.highlighted is None:
        listing.highlighted = 0
    self._show_proposal_list()

on_option_list_option_selected

on_option_list_option_selected(event)

Opens the chosen file or proposal.

Parameters:

Name Type Description Default
event OptionSelected

The choice.

required
Source code in src/trading_agent/terminal/screens/files_screen.py
def on_option_list_option_selected(
    self, event: widgets.OptionList.OptionSelected
) -> None:
    """Opens the chosen file or proposal.

    Args:
        event (widgets.OptionList.OptionSelected): The choice.
    """
    event.stop()
    if event.option_list.id == 'files-list':
        self._ask_before_leaving(
            lambda: self._open(self._files[event.option_index])
        )
    else:
        self._ask_before_leaving(
            lambda: self._show_proposal(
                self._shown_proposals[event.option_index]
            )
        )

action_save

action_save()

Saves the open file.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_save(self) -> None:
    """Saves the open file."""
    if self._open_file is not None:
        self._save()

action_revert

action_revert()

Puts back the text as it was last saved.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_revert(self) -> None:
    """Puts back the text as it was last saved."""
    if self._open_file is not None:
        self.query_one(
            '#files-editor', widgets.TextArea
        ).text = self._saved_text

action_accept

action_accept()

Accepts the shown proposal, changing its file.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_accept(self) -> None:
    """Accepts the shown proposal, changing its file."""
    if (
        self._open_proposal is not None
        and self._open_proposal.get('status') == 'pending'
    ):
        self._decide(True)

action_reject

action_reject()

Rejects the shown proposal.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_reject(self) -> None:
    """Rejects the shown proposal."""
    if (
        self._open_proposal is not None
        and self._open_proposal.get('status') == 'pending'
    ):
        self._decide(False)

action_toggle_decided

action_toggle_decided()

Shows or hides proposals that were already accepted or rejected.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_toggle_decided(self) -> None:
    """Shows or hides proposals that were already accepted or rejected."""
    self._show_decided = not self._show_decided
    self._show_proposal_list()

action_back

action_back()

Goes back to the chat, asking first when the open file has unsaved changes.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_back(self) -> None:
    """Goes back to the chat, asking first when the open file has unsaved changes."""
    self._ask_before_leaving(self.app.pop_screen)

DiscardDialog

DiscardDialog(file_name)

Bases: ModalScreen[bool]

Asks whether to discard unsaved changes to a file.

Creates the dialog.

Parameters:

Name Type Description Default
file_name str

The file with unsaved changes.

required
Source code in src/trading_agent/terminal/screens/files_screen.py
def __init__(self, file_name: str):
    """Creates the dialog.

    Args:
        file_name (str): The file with unsaved changes.
    """
    super().__init__(classes='picker-screen')
    self._file_name = file_name

compose

compose()

Builds the dialog.

Yields:

Type Description
Widget

The question and the keys.

Source code in src/trading_agent/terminal/screens/files_screen.py
def compose(self):
    """Builds the dialog.

    Yields:
        Widget: The question and the keys.
    """
    with containers.Vertical(classes='picker'):
        yield widgets.Static(
            Content.from_markup(
                '[b]$name has unsaved changes.[/b]\nDiscard them?',
                name=self._file_name,
            )
        )
        yield widgets.Static(
            '[dim]y discard · n keep editing[/dim]', classes='picker-hint'
        )

action_discard

action_discard()

Discards the changes.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_discard(self) -> None:
    """Discards the changes."""
    self.dismiss(True)

action_keep

action_keep()

Keeps editing.

Source code in src/trading_agent/terminal/screens/files_screen.py
def action_keep(self) -> None:
    """Keeps editing."""
    self.dismiss(False)