Skip to content
Development
Skill

/inline-editor

Inline text editing implementation within the file browser preview pane using tmux PTY backend, cursor movement, text manipulation, and editor state management. Covers entry/exit lifecycle, dimension calculations, confirmation dialogs, click-away detection, mouse forwarding, and

From plugin
sidecar
1k17 skills
Install
$ npx -y skills add marcus/sidecar --skill inline-editor --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/inline-editor

Context preview

The summary Claude sees to decide when to auto-load this skill.

Inline text editing implementation within the file browser preview pane using tmux PTY backend, cursor movement, text manipulation, and editor state management. Covers entry/exit lifecycle, dimension calculations, confirmation dialogs, click-away detection, mouse forwarding, and

SKILL.md

inline-editor.SKILL.md
name: inline-editor
description: >
  Inline text editing implementation within the file browser preview pane using
  tmux PTY backend, cursor movement, text manipulation, and editor state
  management. Covers entry/exit lifecycle, dimension calculations, confirmation
  dialogs, click-away detection, mouse forwarding, and app-level key routing.
  Use when working on inline editing features, text input components, or
  debugging editor rendering/input issues in the file browser plugin.

Inline Editor Implementation

Overview

The inline editor (`tmux_inline_edit`) lets users edit files directly within the file browser preview pane using their preferred terminal editor (vim, nvim, nano, etc.) without leaving the TUI. The file tree remains visible during editing.

**Core Principle**: This is NOT a terminal emulator. Tmux manages the PTY backend; Sidecar acts as an input/output relay, similar to the workspace plugin's interactive mode.

Architecture

Components

1. **Entry Layer** (`internal/plugins/filebrowser/inline_edit.go`): Creates tmux sessions, manages editor lifecycle 2. **Rendering Layer** (`internal/plugins/filebrowser/view.go`, `inline_edit.go`): Renders editor content within preview pane 3. **Input Layer** (`internal/plugins/filebrowser/plugin.go`, `mouse.go`): Routes keys/clicks to editor or confirmation dialog 4. **TTY Model** (`internal/tty/tty.go`): Handles tmux capture, cursor overlay, and input forwarding

Data Flow

User presses 'e' on file
  -> enterInlineEditMode()
  -> tmux new-session -d -s {sessionName} {editor} {path}
  -> InlineEditStartedMsg
  -> handleInlineEditStarted()
  -> tty.Model.Enter()
  -> Start polling tmux capture-pane
  -> renderInlineEditorContent() in preview pane
  -> User types -> tty.Model forwards to tmux
  -> User exits -> SessionDeadMsg or exit keys
  -> exitInlineEditMode()
  -> Refresh preview

Key Files

| File | Purpose | |------|---------| | `internal/plugins/filebrowser/inline_edit.go` | Editor lifecycle, confirmation dialog, dimension calculations | | `internal/plugins/filebrowser/view.go` | Preview pane rendering, gradient border | | `internal/plugins/filebrowser/mouse.go` | Click-away detection | | `internal/plugins/filebrowser/plugin.go` | State management, Update routing | | `internal/tty/tty.go` | TTY model for tmux interaction (shared with workspace) | | `internal/app/update.go` | App-level key routing for inline edit context |

Critical Implementation Details

1. Preview Pane Rendering (Not Full-Screen)

The editor renders within `renderPreviewPane()`, NOT as a full-screen takeover. The file tree stays visible.

// view.go - renderPreviewPane()
func (p *Plugin) renderPreviewPane(visibleHeight int) string {
    if p.inlineEditMode && p.inlineEditor != nil && p.inlineEditor.IsActive() {
        return p.renderInlineEditorContent(visibleHeight)
    }
    // ... normal preview rendering
}

2. Dimension Calculations

The tty.Model needs exact dimensions matching the preview pane content area:

func (p *Plugin) calculateInlineEditorWidth() int {
    if !p.treeVisible {
        return p.width - 4 // borders + padding
    }
    p.calculatePaneWidths()
    return p.previewWidth - 4
}

func (p *Plugin) calculateInlineEditorHeight() int {
    paneHeight := p.height
    innerHeight := paneHeight - 2 // pane borders
    contentHeight := innerHeight - 2 // header lines
    if len(p.tabs) > 1 {
        contentHeight-- // tab line
    }
    return contentHeight
}

**These MUST stay in sync with `renderInlineEditorContent()` layout calculations.**

3. Confirmation Behavior

**Rule: session alive = show confirmation, session dead = exit immediately.**

Always show confirmation when the session is alive, regardless of file modification status. Vim's modification status cannot be reliably detected externally.

func (p *Plugin) isInlineEditSessionAlive() bool {
    if p.inlineEditSession == "" {
        return false
    }
    err := exec.Command("tmux", "has-session", "-t", p.inlineEditSession).Run()
    return err == nil
}

Check session alive status: 1. At the start of `Update()` when in inline edit mode - if dead, exit immediately 2. In click-away handling - if dead, skip confirmation and clean up

4. Exit Confirmation Dialog

State fields:

showExitConfirmation bool        // Dialog visible
pendingClickRegion   string      // Where user clicked
pendingClickData     interface{} // Click data (tree index, tab index)
exitConfirmSelection int         // 0=Save&Exit, 1=Exit without saving, 2=Cancel

Options:

  • **Save & Exit**: Sends editor-appropriate save-and-quit sequence, waits for session death
  • **Exit without saving**: Kills tmux session immediately
  • **Cancel**: Returns to editing

5. Click-Away Detection

Mouse regions are registered during render. Clicks between items may miss regions, so always include position-based fallback:

if p.inlineEditMode && p.inlineEditor != nil && p.inlineEditor.IsActive() {
    action := p.mouseHandler.HandleMouse(msg)

    handleClickAway := func(regionID string, regionData interface{}) (*Plugin, tea.Cmd) {
        if !p.isInlineEditSessionAlive() {
            p.exitInlineEditMode()
            p.pendingClickRegion = regionID
            p.pendingClickData = regionData
            return p.processPendingClickAction()
        }
        p.pendingClickRegion = regionID
        p.pendingClickData = regionData
        p.showExitConfirmation = true
        p.exitConfirmSelection = 0
        return p, nil
    }

    if action.Type == mouse.ActionClick {
        if action.Region != nil {
            switch action.Region.ID {
            case regionTreePane, regionTreeItem, regionPreviewTab:
                return handleClickAway(action.Region.ID, action.Region.Data)
            }
        }
        // Fallback: position-based detection
        if p.treeVisible && action.X < p.treeWidth {
            return handleClickAw
Read more
Ships withsidecar

You might never open your editor again. Status: Ready for daily use. Please report any issues you encounter.

Get the whole plugin
Stats
1,044
Stars
79
Forks
Active
Maintenance
Go
Language
MIT
License
23m ago
Last commit
7mo ago
Created

Repo: marcus/sidecar

Other skills on sidecar.