Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion extensions/pi-glowup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ Global settings are stored in `~/.pi/agent/extension-settings/pi-glowup.json`.
| `scriptPreview.showPrologueOmission` | boolean | `false` | Show a count row when collapsed previews omit leading setup imports. |
| `scriptPreview.shellLayout` | `preserve` \| `auto` \| `always` | `"auto"` | Choose when composed Bash commands are reflowed at safe syntax boundaries. |
| `scriptPreview.shellOperatorPosition` | `trailing` \| `leading` | `"trailing"` | Place Bash chain operators before or after reflowed line breaks. |
| `scriptPreview.formatters` | Record<string, string[]> | `{}` | Commands that format script previews through stdin/stdout. |
| `scriptPreview.formatters` | Record<string, CommandFormatter \| PythonFormatter \| JavaScriptFormatter \| TypeScriptFormatter \| BashFormatter> | `{}` | Display-only profiles keyed by matching language id; expansion shows original source. |

### Defaults

```json
{
Expand Down Expand Up @@ -154,6 +156,32 @@ Global settings are stored in `~/.pi/agent/extension-settings/pi-glowup.json`.
}
}
```

### Advanced example

```json
{
"$schema": "./schemas/pi-glowup.schema.json",
"scriptPreview": {
"formatters": {
"javascript": {
"kind": "javascript",
"command": [
"oxfmt"
],
"objectWrap": "collapse"
},
"python": {
"kind": "python",
"command": [
"tuff"
],
"collections": "ruff-default"
}
}
}
}
```
<!-- pi-extension-settings:end -->

## License
Expand Down
268 changes: 261 additions & 7 deletions extensions/pi-glowup/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -507,15 +507,269 @@
"type": "object",
"patternProperties": {
"^.*$": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"minItems": 1
"anyOf": [
{
"type": "object",
"required": [
"kind",
"command"
],
"properties": {
"kind": {
"type": "string",
"const": "command",
"description": "Run custom argv without generated formatter configuration."
},
"command": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"pattern": "^[^\\u0000]+$"
},
"minItems": 1,
"description": "Executable followed by arguments; no shell expansion is performed."
}
},
"additionalProperties": false,
"title": "CommandFormatter"
},
{
"type": "object",
"required": [
"kind",
"command"
],
"properties": {
"kind": {
"type": "string",
"const": "python",
"description": "Use Tuff's Python formatter."
},
"command": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"pattern": "^[^\\u0000]+$"
},
"minItems": 1,
"description": "Executable followed by arguments; no shell expansion is performed."
},
"imports": {
"anyOf": [
{
"type": "string",
"const": "show"
},
{
"type": "string",
"const": "omit"
}
],
"description": "Leading import/setup visibility in collapsed display; expansion shows original source.",
"default": "omit"
},
"indentWidth": {
"type": "integer",
"minimum": 1,
"default": 4,
"description": "Python indentation width."
},
"collections": {
"anyOf": [
{
"type": "string",
"const": "fill"
},
{
"type": "string",
"const": "ruff-default"
}
],
"default": "ruff-default",
"description": "Collapse collections that fit; fill instead packs items within multiline brackets."
},
"magicTrailingComma": {
"type": "boolean",
"default": false,
"description": "Treat trailing commas as requests for vertical expansion."
}
},
"additionalProperties": false,
"title": "PythonFormatter"
},
{
"type": "object",
"required": [
"kind",
"command"
],
"properties": {
"kind": {
"type": "string",
"const": "javascript",
"description": "Use Oxfmt's JavaScript parser."
},
"command": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"pattern": "^[^\\u0000]+$"
},
"minItems": 1,
"description": "Executable followed by arguments; no shell expansion is performed."
},
"imports": {
"anyOf": [
{
"type": "string",
"const": "show"
},
{
"type": "string",
"const": "omit"
}
],
"description": "Leading import/setup visibility in collapsed display; expansion shows original source.",
"default": "omit"
},
"tabWidth": {
"type": "integer",
"minimum": 1,
"default": 2,
"description": "Oxfmt indentation width."
},
"objectWrap": {
"anyOf": [
{
"type": "string",
"const": "collapse"
},
{
"type": "string",
"const": "preserve"
}
],
"default": "collapse",
"description": "Collapse object literals when they fit the actual content width."
}
},
"additionalProperties": false,
"title": "JavaScriptFormatter"
},
{
"type": "object",
"required": [
"kind",
"command"
],
"properties": {
"kind": {
"type": "string",
"const": "typescript",
"description": "Use Oxfmt's TypeScript parser."
},
"command": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"pattern": "^[^\\u0000]+$"
},
"minItems": 1,
"description": "Executable followed by arguments; no shell expansion is performed."
},
"imports": {
"anyOf": [
{
"type": "string",
"const": "show"
},
{
"type": "string",
"const": "omit"
}
],
"description": "Leading import/setup visibility in collapsed display; expansion shows original source.",
"default": "omit"
},
"tabWidth": {
"type": "integer",
"minimum": 1,
"default": 2,
"description": "Oxfmt indentation width."
},
"objectWrap": {
"anyOf": [
{
"type": "string",
"const": "collapse"
},
{
"type": "string",
"const": "preserve"
}
],
"default": "collapse",
"description": "Collapse object literals when they fit the actual content width."
}
},
"additionalProperties": false,
"title": "TypeScriptFormatter"
},
{
"type": "object",
"required": [
"kind",
"command"
],
"properties": {
"kind": {
"type": "string",
"const": "bash",
"description": "Use shfmt's Bash formatter without minification."
},
"command": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"pattern": "^[^\\u0000]+$"
},
"minItems": 1,
"description": "Executable followed by arguments; no shell expansion is performed."
},
"indentWidth": {
"type": "integer",
"minimum": 1,
"default": 2,
"description": "Bash indentation width."
},
"caseIndent": {
"type": "boolean",
"default": true,
"description": "Indent Bash case arms."
},
"spaceRedirects": {
"type": "boolean",
"default": true,
"description": "Separate redirect operators from targets."
},
"binaryNextLine": {
"type": "boolean",
"default": false,
"description": "Start continued Bash chains with their operator."
}
},
"additionalProperties": false,
"title": "BashFormatter"
}
]
}
},
"description": "Commands that format script previews through stdin/stdout."
"description": "Display-only profiles keyed by matching language id; expansion shows original source."
}
},
"additionalProperties": false,
Expand Down
45 changes: 35 additions & 10 deletions extensions/pi-glowup/docs/script-previews.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Reflowed chain and case operators stay at the end of the preceding row by defaul

Reflow uses the Bash syntax tree to place logical operators, pipelines, statements, and compound
shell bodies on readable rows. It retains the original shell tokens, never extracts language
blocks from a composed command, and leaves submitted multiline commands and heredocs unchanged.
blocks from a composed command, and preserves existing newlines, quoted text, and heredoc bodies.
Only clean standalone interpreter calls render as Python, Node, TypeScript, Bun, or Deno previews.
Single-quoted inline source inside a composed command remains in the Bash block but receives its
language's syntax highlighting when the interpreter can be identified safely.
Expand All @@ -41,20 +41,45 @@ language's syntax highlighting when the interpreter can be identified safely.

Collapsed script previews show up to `scriptPreview.maxCodePreviewLines` lines before adding a
hint with Pi's configured tool-expansion key. The default is `8`, and values below `4` are rejected
so four-line-or-shorter previews are never truncated.
while wrapping also counts against the terminal-row budget.

Short scripts keep their imports. Long Python, JavaScript, and TypeScript previews silently omit
Unformatted short scripts keep their imports. Long Python, JavaScript, and TypeScript previews omit
only a complete leading import/setup prologue. Set `scriptPreview.showPrologueOmission` to `true`
to show the omitted-line count. Expanding the tool call always restores the complete code.

## Formatters

Script previews are not formatted by default. Configure `scriptPreview.formatters` to map rendered language ids to formatter command argv arrays.
Formatting is off by default. `scriptPreview.formatters` maps language ids to explicit profiles:

Formatters apply to clean standalone language calls and codemode JavaScript blocks. Composed Bash
commands are never passed to a language formatter. Successful formatter output is cached by
language, target width, and source for the session.

`pi-glowup` dynamically adapts formatting to the available terminal rendering width. You can use `{width}`, `{line_length}`, or `{cols}` placeholders in your command arguments (e.g. `["tuff", "format", "--line-length", "{width}", "--stdin-filename", "script.py", "-"]`), and `pi-glowup` will also automatically export environment variables (`TUFF_LINE_LENGTH`, `RUFF_LINE_LENGTH`, `COLUMNS`) containing the available content width for tool rendering.
```json
{
"javascript": { "kind": "javascript", "command": ["oxfmt"], "objectWrap": "collapse" },
"typescript": { "kind": "typescript", "command": ["oxfmt"], "tabWidth": 2 },
"python": { "kind": "python", "command": ["tuff"], "collections": "ruff-default" },
"bash": { "kind": "bash", "command": ["shfmt"], "indentWidth": 2 }
}
```

Formatter failures, missing commands, invalid JSON, and empty output are ignored; the original script preview is rendered unchanged.
Python collapses collections that fit, ignores magic trailing commas by default, and retains
comments and literal contents. Explicit `collections: "fill"` keeps multiline brackets and packs rows. JavaScript/TypeScript use Oxfmt object collapse and two-space
indentation. Bash uses two-space shfmt without simplification or minification; only a Bash profile
formats whole shell commands. Executables must already be installed and reachable, or use an
explicit executable path. `kind: "command"` accepts arbitrary formatter argv through `command`.

Profiles format asynchronously at the available content width and after resize. Oxfmt receives
`printWidth` through an owned temporary configuration; Tuff receives line length and an isolated
collection profile. Blank-line decisions belong to the formatter, never a text-stripping pass.
Python/JS/TS profiles omit complete leading imports by default; `imports: "show"` retains them.
Bash keeps setup statements and heredocs. Expanded Bash-tool and Codemode previews show original source.

Streaming previews keep raw source until execution completes. Prepared decoration is then
published in one update, or once ready if the result arrives first. Formatting never delays tool
execution or changes submitted arguments. Successful output is cached by language, width, and
source. Command profiles also accept `{width}`, `{line_length}`, and `{cols}` argv placeholders.
Missing or failed executables produce a content-free warning; undecorated source remains visible.

## Highlighting

Code within the 40 KiB source budget is tokenized off the TUI thread without a logical-line cutoff.
Plain source remains visible while full grammar-aware colors are pending. Superseded work is cancelled;
the existing cache budgets remain. Tokenizer CPU time is not bounded by an elapsed-time limit.
Loading
Loading