Files
Newton-Editor/AGENTS.md
itdominator 608699c431 refactor(command-system): standardize command execution with *args/**kwargs
- Refactor exec_with_args to use *args/**kwargs instead of tuple arguments
- Add *args/**kwargs to all command execute functions for consistency
- Support multiple key bindings per command in registration
- Add character-based key binding support via get_char() in KeyMapper
- Make execute_plugin async and use asyncio.run for plugin execution
- Use MIME type from Gio content_type instead of language for ftype
2026-02-24 22:30:44 -06:00

5.9 KiB

AGENTS.md - Development Guidelines for Newton

Overview

Newton is a Python/Gtk3 desktop application (code editor) using PyGObject. The project follows specific conventions documented below.


Build, Lint, and Test Commands

Running the Application

# Activate virtual environment and run
source .venv/bin/activate
python -m src

Type Checking (Pyright)

The project uses pyright for static type checking. Configuration is in pyrightconfig.json:

# Run pyright (ensure venv is activated)
pyright src/

# Or via Python module
python -m pyright src/

pyrightconfig.json settings:

  • venvPath: "."
  • venv: ".venv"
  • Reports: unused variables, unused imports, duplicate imports

No Test Framework

There are currently no tests in this codebase. If tests are added:

  • Use pytest as the testing framework
  • Test files should be in a tests/ directory
  • Run a single test: pytest tests/test_file.py::test_function_name

Code Style Guidelines

Import Organization

Imports must be organized with blank lines between groups (in this exact order):

# Python imports
import os
import logging

# Lib imports
import gi
gi.require_version('Gtk', '3.0')

from gi.repository import Gtk
from gi.repository import GLib

# Application imports
from libs.dto.states import SourceViewStates
from .mixins.source_view_dnd_mixin import SourceViewDnDMixin

Type Hints

  • Use type hints for all function parameters and return types
  • Use Python's built-in types (list[str], dict[str, int]) not typing module aliases
  • Example: def message_to(self, name: str, event: BaseEvent):

Naming Conventions

Element Convention Example
Classes PascalCase ControllerBase, SourceView
Methods/Variables snake_case set_controller_context, _cut_buffer
Private methods Leading underscore _setup_styles, _subscribe_to_events
Constants UPPER_SNAKE_CASE LOG_LEVEL, DEFAULT_ZOOM
Exception classes PascalCase ending in Exception ControllerBaseException

Class Structure

class MyClass(Singleton, EmitDispatcher):
    def __init__(self):
        super(MyClass, self).__init__()

        self.controller_context: ControllerContext = None
        self._private_var = None

    def public_method(self, param: str) -> None:
        ...

    def _private_method(self) -> None:
        ...

Placeholder Methods

Use ellipsis ... for unimplemented methods or abstract-like methods:

def _subscribe_to_events(self):
    ...

Dataclasses for DTOs/Events

Use @dataclass for data transfer objects and events:

from dataclasses import dataclass, field

@dataclass
class TextInsertedEvent(CodeEvent):
    location: Gtk.TextIter = None
    text: str              = ""
    length: int            = 0

Error Handling

  • Custom exceptions should end with Exception
  • Use raise ValueError("message") for validation errors
  • Let exceptions propagate for unexpected errors

Singleton Pattern

Classes requiring singleton behavior should inherit from Singleton:

from libs.singleton import Singleton

class MySingleton(Singleton):
    ...

GTK/Widget Conventions

  • Call _setup_styles(), _setup_signals(), _subscribe_to_events(), _load_widgets() in __init__
  • Use self.connect("signal-name", self._handler) for GTK signals
  • Private GTK attributes use underscore prefix: self._cut_temp_timeout_id

Code Formatting

  • Use spaces around operators: x = value, not x=value
  • Align assignments with spaces for related variables:
    self.state                = state
    self._cut_temp_timeout_id = None
    
  • Maximum line length: Let pyright/editor handle warnings (typically 80-120 chars)

No Comments

DO NOT add comments to code unless explicitly required. Write self-documenting code.


Project Structure

Newton/
├── src/
│   ├── app.py              # Main application entry
│   ├── __main__.py         # Module entry point
│   ├── __builtins__.py     # Built-in definitions
│   ├── core/               # Core UI components
│   │   ├── containers/     # Layout containers
│   │   ├── controllers/    # Controllers
│   │   └── widgets/        # GTK widgets
│   ├── libs/               # Core libraries
│   │   ├── controllers/    # Controller infrastructure
│   │   ├── db/             # Database (SQLModel)
│   │   ├── dto/            # Data transfer objects
│   │   ├── mixins/         # Mixin classes
│   │   └── settings/       # Settings management
│   └── plugins/            # Plugin system
├── plugins/                # Plugin implementations
├── user_config/            # User configuration files
├── requirements.txt        # Python dependencies
└── pyrightconfig.json      # Pyright configuration

Key Libraries Used

  • PyGObject (GTK3) - GUI framework
  • sqlmodel - Database (SQLAlchemy + Pydantic)
  • setproctitle - Process title management
  • pyxdg - XDG desktop file parsing

Common Patterns

Creating a New Controller

from libs.controllers.controller_base import ControllerBase
from libs.controllers.controller_context import ControllerContext

class MyController(ControllerBase):
    def __init__(self):
        super().__init__()
        self.controller_context = None

    def _controller_message(self, event: BaseEvent):
        # Handle events
        pass

Creating a New Event/DTO

from dataclasses import dataclass
from libs.dto.code.code_event import CodeEvent

@dataclass
class MyEvent(CodeEvent):
    field1: str = ""
    field2: int = 0

Connecting to Events

from libs.event_system import EventSystem

event_system = EventSystem()
event_system.subscribe("event_name", self.my_handler)