PyPositron Docs

Getting Started with PyPositron

Welcome to PyPositron! This guide will walk you through creating your first project, understanding the example code, and building a simple code editor.

Step 1: Create the Example Project

To create the example project, follow the instructions in the Quick Start guide. If you have already created the example project, you can skip this step.

Step 2: Understand the Example Code

The example project consists of two main files:

backend/main.py

This file contains the Python logic for your application.

import py_positron as positron
import time

def main(ui: positron.PositronWindowWrapper):
    button = ui.document.getElementById("button")
    def on_click():
        current_time = time.strftime("%H:%M:%S")
        ui.document.alert(f"The current time is {current_time}")
    button.addEventListener("click", on_click)

def after_close(ui: positron.PositronWindowWrapper):
    print("Closing...")

positron.openUI("frontend/index.html", main, after_close, title="Example App")

main(ui: positron.PositronWindowWrapper)

  • Called when the UI window starts loading.
  • ui.document.getElementById() finds the button element by its id.
  • Defines an on_click callback that:
    1. Gets the current system time.
    2. Formats it as HH:MM:SS.
    3. Displays it via ui.document.alert.
  • Attaches that callback to the button’s "click" event using addEventListener().

after_close(ui: positron.PositronWindowWrapper)

  • This is optional.
  • Called after the UI window is closed.
  • Used for cleanup or logging.
  • Here, it simply prints "Closing..." to the console.

frontend/index.html

This file contains the HTML and CSS for your application's user interface.

<!DOCTYPE html>
<html>
<head>
    <title>Python-Powered App</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 20px;
        }
        button {
            padding: 10px 20px;
            font-size: 16px;
        }
    </style>
</head>
<body>
    <h1>Welcome to PyPositron!</h1>
    <button id="button">Click Me</button>
</body>
</html>

This is a fairly simple HTML file that:

  • Sets the document type to HTML5.
  • Defines a <head> section with a title and some basic CSS styles.
  • Contains a <body> section with a heading and a button.

Step 3: Modify the Example Code

Add a Textbox

Update frontend/index.html to include a textbox:

<!-- in the body section of index.html -->
<h2>Type Something</h2>
<input type="text" id="textbox" placeholder="Type something...">

Example: Handle Key Press Events

We will update backend/main.py to handle key press events:

    # in main...

    textbox = ui.document.getElementById("textbox") # Get the textbox element

    def on_key_press():
        value = textbox.value
        print(f"You typed: {value}")
    textbox.addEventListener("keypress", on_key_press)
  • The on_key_press function retrieves the value of the textbox and prints it to the console whenever a key is pressed.
  • Then, we attach this function to the textbox's "keypress" event using addEventListener().
  • The textbox.value property is used to get the current text in the textbox. This property can also be used to set the value of the textbox programmatically.

Step 4: Build a Code Editor

Use a CSS Framework

To style your code editor, include a CSS framework like Bootstrap in frontend/index.html:

<!--in the head section of index.html -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">

Add a Code Editor Area

Update frontend/index.html to include a textarea for the code editor, a file path input, and a button to execute the code:

<div id="editor-container" class="container-fluid mt-3">
    <label for="code-editor" class="form-label">Code Editor</label>
    <textarea id="code-editor" class="form-control"></textarea>
</div>
<div class="container-fluid mb-3">
    <label for="file-path" class="form-label mb-0">File Path</label>
    <div class="d-flex align-items-center gap-3 mt-2">
        <input type="text" id="file-path" class="form-control flex-grow-1">
        <button id="save-button" class="btn btn-primary">Save</button>
        <span id="save-button-span" class="text-success">No code saved yet. Press the save button.</span>
    </div>
</div>
  • The <textarea> element with id="code-editor" will be used for writing code.
  • The mb-3 class adds a bottom margin to the container.
  • Inside the d-flex container:
    • The <input> element with id="file-path" allows the user to specify a file path where the code will be saved.
    • The <button> with id="save-button" will trigger the save action.
    • The <span> with id="save-button-span" will display feedback after saving the code.
    • The flex-grow-1 class makes the input field take up the remaining space in the flex container.
  • The d-flex class makes the container a flexbox, allowing for easy alignment of its children.

Style the Code Editor

Create a new CSS file frontend/index.css and link it in index.html:

<!-- in the head section of index.html -->
<link rel="stylesheet" href="index.css">

Then, add some styles to frontend/index.css:

html, body {
        margin: 0;
        padding: 0;
        height: 100%;
        display: flex;
        flex-direction: column;
        background: #121212;
        color: #ffffff;
    }
    /* Editor container fills available space */
    #editor-container {
        flex: 1;
        display: flex;
        flex-direction: column;
    }
    label[for="code-editor"] {
        margin-bottom: 5px;
    }
    #code-editor {
        flex: 1;
        width: 100%;
        padding: 10px;
        font-family: monospace;
        font-size: 14px;
        color: #ffffff;
        background: #1e1e1e;
        border: 1px solid #333;
        border-radius: 0;
        resize: none;
        box-sizing: border-box;
    }
    /* Bottom controls */
    .mb-3 {
        padding: 10px;
    }
    input#file-path{
        padding: 10px;
        border-radius: 0;
    }
    button#save-button {
        border-radius: 0;
    }
  • The html and body styles set the background color and text color for the entire page.
    • In this case, a dark theme is applied by making background black and color (which is text color) white.
  • The #editor-container fills the available space and uses flexbox to arrange its children vertically.
    • The flex: 1 property allows the editor container to expand and fill the available vertical space.
    • The display: flex and flex-direction: column properties make the container a flexbox that arranges its children in a column.
  • The #code-editor styles apply to the textarea:
    • A separate, lighter background color is applied to the editor container to differentiate it from the rest of the page.
    • width: 100% ensures the textarea takes the full width of its container.
    • The padding property adds space inside the textarea for better readability.
    • The font-family is set to monospace for a code-like appearance.
    • Setting border-radius: 0 gives it a square corner look.
    • The resize: none property prevents the user from resizing the textarea. By default, textareas can be resized by the user, but in this case, we want to keep it fixed in size.

Save Code

Update backend/main.py to save the code written in the editor:

# in main...
code_editor = ui.document.getElementById("code-editor")
path_input = ui.document.getElementById("file-path")

def save_code():
    code = code_editor.value
    path = path_input.value
    with open(path, "w") as f:
        f.write(code)

save_button = ui.document.getElementById("save-button")
save_button.addEventListener("click", save_code)
  • The save_code function retrieves the code from the textarea and the file path from the input field, then writes the code to the specified file. This is set as the click event handler for the save button.
  • The .value property of the textarea and input field is used to get their current values.

Final code

frontend/index.html

<!DOCTYPE html>
<html>
<head>
    <title>Code Editor</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <div id="editor-container" class="container-fluid mt-3">
        <label for="code-editor" class="form-label">Code Editor</label>
        <textarea id="code-editor" class="form-control"></textarea>
    </div>
    <div class="container-fluid mb-3">
        <label for="file-path" class="form-label mb-0">File Path</label>
        <div class="d-flex align-items-center gap-3 mt-2">
            <input type="text" id="file-path" class="form-control flex-grow-1">
            <button id="save-button" class="btn btn-primary">Save</button>
            <span id="save-button-span" class="text-success">No code saved yet. Press the save button.</span>
        </div>
    </div>
</body>
</html>

frontend/index.css

html, body {
        margin: 0;
        padding: 0;
        height: 100%;
        display: flex;
        flex-direction: column;
        background: #121212;
        color: #ffffff;
    }
    /* Editor container fills available space */
    #editor-container {
        flex: 1;
        display: flex;
        flex-direction: column;
    }
    label[for="code-editor"] {
        margin-bottom: 5px;
    }
    #code-editor {
        flex: 1;
        width: 100%;
        padding: 10px;
        font-family: monospace;
        font-size: 14px;
        color: #ffffff;
        background: #1e1e1e;
        border: 1px solid #333;
        border-radius: 0;
        resize: none;
        box-sizing: border-box;
    }
    /* Bottom controls */
    .mb-3 {
        padding: 10px;
    }
    input#file-path{
        padding: 10px;
        border-radius: 0;
    }
    button#save-button {
        border-radius: 0;
    }

backend/main.py

import py_positron as positron
import time

def main(ui: positron.PositronWindowWrapper):
    code_editor = ui.document.getElementById("code-editor")
    path_input = ui.document.getElementById("file-path")
    save_button_span = ui.document.getElementById("save-button-span")
    save_button = ui.document.getElementById("save-button")
    def save_code():
        code = code_editor.value
        path = path_input.value
        with open(path, "w") as f:
            f.write(code)
        save_button_span.innerText = str(len(code.split("\n"))) + " lines of code saved to: " + path  # Show feedback 
    save_button.addEventListener("click", save_code)

def after_close(ui: positron.PositronWindowWrapper):
    print("Closing...")


positron.openUI("frontend/index.html", main, after_close, title="Code Editor")

Run and test the application

To run your application, like before, navigate to your project directory in the terminal and execute:

positron start

This will open the UI window defined in your backend/main.py file, loading frontend/index.html by default.

Congratulations! You have created a simple code editor application using PyPositron. You can now type code into the editor, specify a file path, and save the code to that file.
You can now use PyPositron to build more complex applications by adding more features and functionality.

Next Steps

  • Library Reference: Learn more about PyPositron's classes and methods.
  • Troubleshooting: Find solutions to common issues.
  • Learn HTML, CSS, and JavaScript (Mozilla Developer Network): Familiarize yourself with web development basics to enhance your UI.
  • Extend the code editor with features like syntax highlighting, file reading, a code execution feature and/or terminal, and a project/directory sidebar to select files.
  • Build an actual app and share it with the community!