Skip to content

Latest commit

 

History

History
566 lines (412 loc) · 20.3 KB

File metadata and controls

566 lines (412 loc) · 20.3 KB

Fresh User Guide

Welcome to Fresh, a fast, extensible, and powerful terminal text editor. This guide will walk you through the core features of Fresh and help you get started with using and configuring the editor.

Getting Started

Installation

See the Installation section in the README for all available installation methods, including Homebrew, AUR, .deb/.rpm packages, npm, crates.io, and building from source.

Running Fresh

To run Fresh, you can either open it without a file, or specify a file to open:

# Open an empty buffer
fresh

# Open a file
fresh src/main.rs

Core Concepts

  • The Command Palette: The command palette is your central hub for accessing all of Fresh's features. Press Ctrl+P to open it, and then start typing to search for commands.
  • Buffers: Each open file is represented as a buffer. You can have multiple buffers open at once and switch between them.
  • Splits: You can split your editor view horizontally or vertically to view multiple buffers at once.
  • The Status Bar: The status bar at the bottom of the screen displays information about the current buffer, including the file name, cursor position, and Git branch.

Core Features

Editing

Fresh provides a powerful set of editing features to help you be more productive.

  • Multiple Cursors: Use Ctrl+D to select the next occurrence of the current word and create a new cursor. This allows you to edit multiple places in your code at once.
  • Advanced Selection: Fresh provides a variety of ways to select text, including word selection (Ctrl+W), line selection (Ctrl+L), and expanding the selection incrementally.
  • Unlimited Undo/Redo: Fresh has a complete edit history, so you can undo and redo changes as much as you need to.

Navigation

  • Go to Definition: Use the command palette (Ctrl+P) and search for "Go to Definition" to jump to the definition of a symbol under the cursor (requires LSP).
  • Position History: Navigate back and forward through your edit locations using Alt+Left and Alt+Right.

File Explorer

Fresh includes a built-in file explorer to help you navigate your project's files.

  • Toggle: Use Ctrl+E to open and close the file explorer.
  • Navigation: Use the arrow keys to move up and down the file tree.
  • Open Files: Press Enter to open the selected file.
  • Gitignore Support: The file explorer respects your .gitignore file, hiding ignored files by default.

Search and Replace

Fresh provides a powerful search and replace feature with support for regular expressions and interactive replacement.

  • Search: Press Ctrl+F to open the search prompt.
  • Replace: Press Ctrl+R to open the search and replace prompt.

Integrated Terminal

Fresh includes a built-in terminal emulator that lets you run shell commands without leaving the editor.

Opening a Terminal

  • Command Palette: Press Ctrl+P and search for "Open Terminal"
  • Multiple Terminals: You can open multiple terminal tabs and switch between them like regular file buffers

Terminal Modes

The terminal has two modes, indicated in the status bar:

  1. Terminal Mode (status bar shows "Terminal"): Your keyboard input goes directly to the shell. Use this for typing commands and interacting with programs.

  2. Scrollback Mode (status bar shows "Terminal (read only)"): The terminal output becomes a read-only buffer that you can scroll through, search, and copy text from.

Switching Between Modes

  • Ctrl+Space: Toggle between terminal mode and scrollback mode
  • Ctrl+]: Exit terminal mode (same as Ctrl+Space)

Keyboard Capture

By default, most editor keybindings (like Ctrl+P for command palette) still work in terminal mode. If you need to send these keys to the terminal instead:

  • F9: Toggle keyboard capture mode
  • When keyboard capture is enabled (status bar shows "Terminal [capture]"), all keys except F9 are sent to the terminal
  • Visual indicator: The UI dims (menu bar, status bar, other splits) to clearly show focus is exclusively on the terminal

Scrollback Navigation

In scrollback mode, you can use standard editor navigation:

  • Arrow keys / Page Up / Page Down: Scroll through output
  • Ctrl+Home: Jump to the beginning of scrollback history
  • Ctrl+End: Jump to the end
  • Ctrl+F: Search through terminal output

Tips and Quirks

  • Session Persistence: Terminal sessions are preserved when you close and reopen Fresh. Your scrollback history and running processes are maintained.
  • Automatic Scroll: When new output arrives while you're in scrollback mode, the terminal automatically returns to terminal mode to show the latest output. Disable this with the terminal.jump_to_end_on_output config option.
  • Resizing: The terminal automatically resizes when you resize the editor or split panes.

LSP Integration

Fresh has native support for the Language Server Protocol (LSP), providing features like:

  • Real-time diagnostics: See errors and warnings in your code as you type.
  • Code completion: Get intelligent code completion suggestions.
  • Go-to-definition: Quickly jump to the definition of a symbol.

Configuring LSP for a New Language

To add LSP support for a language, you need to configure two sections in your ~/.config/fresh/config.json:

  1. languages: Define the file extensions for the language
  2. lsp: Configure the language server command

For example, to add C# support:

{
  "languages": {
    "csharp": {
      "extensions": ["cs"],
      "grammar": "c_sharp",
      "comment_prefix": "//",
      "auto_indent": true
    }
  },
  "lsp": {
    "csharp": {
      "command": "/path/to/csharp-language-server",
      "args": [],
      "enabled": true
    }
  }
}

The language name (e.g., "csharp") must match in both sections. Fresh includes built-in language definitions for Rust, JavaScript, TypeScript, and Python, but you can add any language by configuring it in your config file.

Configuring Language Detection via Settings UI

You can also configure language detection using the Settings UI instead of editing config.json directly:

  1. Open Settings: Press Ctrl+, or use the command palette (Ctrl+P) and search for "Settings"
  2. Navigate to Languages: Go to the Languages section
  3. Add or Edit a Language: Click on an existing language to edit it, or add a new one
  4. Configure Detection: Set the following fields:
    • Extensions: File extensions that should use this language (e.g., cs for C#, rs for Rust)
    • Filenames: Specific filenames without extensions (e.g., Makefile, .bashrc, .zshrc)
    • Grammar: The syntax highlighting grammar to use (must match a grammar name from syntect)
Example: Adding Shell Script Detection for Dotfiles

To make Fresh recognize .bashrc, .zshrc, and similar files as shell scripts:

  1. Open Settings (Ctrl+,)
  2. Go to Languagesbash (or create a new bash entry)
  3. Add filenames: .bashrc, .zshrc, .bash_profile, .profile
  4. The grammar should be set to Bourne Again Shell (bash) or similar

Fresh checks filenames first, then extensions, allowing dotfiles without traditional extensions to get proper syntax highlighting.

Plugins

Fresh's functionality can be extended with plugins written in TypeScript. Fresh comes with a few useful plugins out of the box:

  • TODO Highlighter: Highlights TODO, FIXME, and other keywords in your comments.
  • Git Grep: Interactively search through your Git repository.
  • Git Find File: Quickly find and open files in your Git repository.

On macOS, plugins folder needs to live either in the same directory as the binary OR in the directory that fresh is run from. If installed via homebrew, the binary lives in /opt/homebrew/bin/fresh. The simplest, cleanest way to to create a symbolic link in that folder pointing to your plugins. i.e. ln -s /Users/username/freshplugins /opt/homebrew/bin/plugins

Clangd helper plugin

Fresh ships plugins/clangd_support.ts with the source tree; see plugins/clangd_support.md for an overview of the plugin commands and how it surfaces clangd-specific notifications in the status bar.

Configuration

Fresh uses a layered configuration system that allows you to customize settings at different levels of scope.

Configuration Layers

Settings are loaded from multiple layers, with higher layers overriding lower ones:

Layer Location Scope Use Case
System Built-in defaults Global Factory defaults (read-only)
User ~/.config/fresh/config.json All projects Personal preferences
Project .fresh/config.json in project root Single project Project-specific settings
Session .fresh/session.json (temporary) Current session Temporary overrides

Path Notes:

  • On Windows, User config is at %APPDATA%\fresh\config.json
  • Project config is found by searching up from the current directory for .fresh/config.json

How Layers Are Merged

When Fresh loads configuration, it merges all layers together. The merge behavior depends on the type of setting:

Simple Values (strings, numbers, booleans)

Higher layers completely override lower layers. If a setting is not specified in a higher layer, it falls through to the next lower layer.

System: theme = "default"    ← Base default
User:   theme = "dark"       ← Overrides system
Project: (not set)           ← Falls through
Session: theme = "light"     ← Final value: "light"

Nested Objects (editor, terminal, file_explorer)

Nested objects are deep-merged field by field. Each field follows the same "higher wins" rule independently.

Example: If User sets editor.tab_size = 4 and Project sets editor.line_wrap = true:

// User config
{ "editor": { "tab_size": 4, "line_numbers": true } }

// Project config
{ "editor": { "line_wrap": true } }

// Result: All fields merged
{ "editor": { "tab_size": 4, "line_numbers": true, "line_wrap": true } }

Languages Map (deep merge)

The languages map uses deep merging with field-level override:

  • Entries from all layers are combined (you can add new languages at any layer)
  • For the same language key, individual fields are merged (not replaced entirely)

Example: Extending built-in Rust settings in your project:

// System (built-in): rust has extensions, grammar, etc.
// Project config - only need to specify what you're changing:
{
  "languages": {
    "rust": {
      "tab_size": 2,
      "format_on_save": true
    }
  }
}
// Result: Rust keeps all system defaults, with tab_size and format_on_save overridden

LSP Map (shallow merge)

The lsp map uses shallow merging:

  • Entries from all layers are combined
  • For the same language key, the entire config is replaced (not field-merged)

Example: To override just one LSP setting, you must specify the complete config:

{
  "lsp": {
    "rust": {
      "command": "rust-analyzer",
      "args": [],
      "enabled": true,
      "initialization_options": { "checkOnSave": { "command": "clippy" } }
    }
  }
}

Lists (keybindings, on_save actions)

Lists are replaced entirely by higher layers - they are not merged or appended.

Example: If you define keybindings in your Project config, it completely replaces User keybindings (not extends them).

Removing/Unsetting Values

There is currently no explicit mechanism to "remove" or "unset" a value defined in a lower layer. You can only override values with different settings. For boolean settings, you can set them to false to disable a feature enabled in a lower layer.

Using the Settings UI

The easiest way to configure Fresh is through the Settings UI:

  1. Open Settings: Press Ctrl+, or use Command Palette → "Open Settings"
  2. Browse Categories: Use arrow keys or click to navigate
  3. Change Values: Toggle booleans, adjust numbers, select from dropdowns
  4. Choose Target Layer: Click the layer button (e.g., [ User ]) to switch between User/Project/Session
  5. Save: Press Enter on the Save button or use Ctrl+S

Advanced: Edit Config File Directly

For complex configurations (like LSP args or custom keybindings), click the [ Edit ] button in the Settings footer to open the raw JSON config file for the selected layer.

Example Configurations

User config (~/.config/fresh/config.json) - your personal defaults:

{
  "version": 1,
  "theme": "dark",
  "editor": {
    "tab_size": 4,
    "line_numbers": true
  }
}

Project config (.fresh/config.json) - project-specific overrides:

{
  "version": 1,
  "editor": {
    "tab_size": 2
  },
  "languages": {
    "javascript": {
      "formatter": "prettier --write"
    }
  }
}

Common Configuration Tasks

Add a Custom Language

To add syntax highlighting and LSP support for a new language:

{
  "languages": {
    "mylang": {
      "extensions": ["ml", "myl"],
      "grammar": "mylang",
      "comment_prefix": "#",
      "auto_indent": true
    }
  },
  "lsp": {
    "mylang": {
      "command": "mylang-lsp",
      "args": ["--stdio"],
      "enabled": true
    }
  }
}

Customize LSP Settings

Configure initialization options for a language server:

{
  "lsp": {
    "rust": {
      "command": "rust-analyzer",
      "enabled": true,
      "initialization_options": {
        "checkOnSave": { "command": "clippy" }
      }
    }
  }
}

Project-Specific Tab Size

Create .fresh/config.json in your project:

{
  "version": 1,
  "editor": {
    "tab_size": 2
  }
}

Layer Source Indicators

In the Settings UI, each setting shows where its current value comes from:

  • (user) - Set in your User config
  • (project) - Set in the Project config
  • (session) - Temporary session override
  • (no indicator) - Using system default

Process Resource Limits

To prevent LSP servers from consuming too many resources, Fresh can limit their memory and CPU usage. This is configured in the process_limits section of your config.json file.

{
  "lsp": {
    "rust": {
      "command": "rust-analyzer",
      "enabled": true,
      "process_limits": {
        "max_memory_mb": 4096,
        "max_cpu_percent": 200
      }
    }
  }
}

For more information on how to configure resource limits, see the docs/PROCESS_LIMITS.md file.

Keyboard Config

Many OSes, window managers and terminal applications capture keys and filter them out so that applications like Fresh, running in the terminal, don't actually have a chance to handle those keys.

Linux: XFCE window manager Ctrl + Alt + Up/Down keys - Disabling Workspace Switching Shortcuts

Follow these steps to clear the Ctrl + Alt + Up and Ctrl + Alt + Down shortcuts so they can be used in other applications (like fresh).


Step-by-Step Instructions

  1. Open Settings: Open the XFCE Application Menu and go to Settings > Window Manager.
  2. Navigate to Keyboard: Click on the Keyboard tab.
  3. Find Workspace Shortcuts: Scroll through the list of actions to find:
    • Upper workspace
    • Bottom workspace
  4. Clear First Shortcut (Up):
    • Select the row for Upper workspace (usually mapped to Ctrl+Alt+Up).
    • Click the Clear button (or double-click the row and press Backspace).
  5. Clear Second Shortcut (Down):
    • Select the row for Bottom workspace (usually mapped to Ctrl+Alt+Down).
    • Click the Clear button.
  6. Close: Click Close to save the changes.

Configuration Summary

Action Default Shortcut New Setting
Upper workspace Ctrl + Alt + Up Cleared / None
Bottom workspace Ctrl + Alt + Down Cleared / None

Note: If you still experience issues, check Settings > Keyboard > Application Shortcuts to ensure no custom commands are overriding these keys.

macOS: Shift + Arrow Key Shortcuts in Terminal.app

Follow these steps to map Shift + Up and Shift + Down to specific escape sequences in your macOS Terminal.


Step-by-Step Instructions

  1. Open Settings: Launch Terminal and go to Terminal > Settings (or press Cmd + ,).
  2. Navigate to Keyboard: Click the Profiles tab, then select the Keyboard sub-tab.
  3. Add First Shortcut (Cursor Up):
    • Click the Plus (+) icon at the bottom left of the list.
    • Key: Select Cursor Up.
    • Modifier: Select Shift.
    • Action: Select Send Text.
    • Input: Type \033[1;2A
    • Click OK.
  4. Add Second Shortcut (Cursor Down):
    • Click the Plus (+) icon again.
    • Key: Select Cursor Down.
    • Modifier: Select Shift.
    • Action: Select Send Text.
    • Input: Type \033[1;2B
    • Click OK.

Configuration Summary

Shortcut Key Modifier Action Escape Sequence
Shift + Up Cursor Up Shift Send Text \033[1;2A
Shift + Down Cursor Down Shift Send Text \033[1;2B

Troubleshooting

Terminal Color Support

Fresh automatically detects your terminal's color capability and converts theme colors accordingly. Most modern terminals support 24-bit "truecolor", but some terminals and multiplexers have limited support.

Color Modes

  • Truecolor (24-bit): Full RGB color support (16 million colors). Used by modern terminals like Kitty, Alacritty, iTerm2, and most others with COLORTERM=truecolor.
  • 256 colors: Extended palette. Used by xterm-256color and similar terminals.
  • 16 colors: Basic ANSI colors. Used by the Linux console and very old terminals.

Terminal Multiplexers

GNU Screen and tmux add a layer between your terminal and Fresh, which can affect color rendering:

  • GNU Screen: Does not support truecolor. Fresh automatically uses 256 colors when TERM starts with screen.
  • tmux: Supports 256 colors by default. Some configurations support truecolor with TERM=tmux-direct.

Manual Override

If colors look wrong, you can force a specific color mode with the FRESH_COLOR_MODE environment variable:

# Force 256-color mode (recommended for GNU Screen)
FRESH_COLOR_MODE=256 fresh

# Force 16-color mode
FRESH_COLOR_MODE=16 fresh

# Force truecolor (if auto-detection is wrong)
FRESH_COLOR_MODE=truecolor fresh

Common Issues

Symptom Likely Cause Solution
Colors look completely wrong Truecolor detected but not supported Use FRESH_COLOR_MODE=256
Weird artifacts/rendering issues Terminal multiplexer interference Try FRESH_COLOR_MODE=256 or check TERM
Very limited/ugly colors 16-color mode detected Check your terminal supports 256 colors

Checking Your Terminal

# Check TERM variable
echo $TERM

# Check COLORTERM (if set, indicates truecolor support)
echo $COLORTERM

Advanced Topics

Visual Regression Testing

Fresh uses a visual regression testing system to ensure that UI changes are intentional. For more information, see docs/VISUAL_REGRESSION_TESTING.md.

Keybindings

Action Key
General
Command Palette Ctrl+P
Show Keybindings Ctrl+H
File
Open File Ctrl+O
Save File Ctrl+S
Editing
Undo Ctrl+Z
Redo Ctrl+Y
Select Next Occurrence Ctrl+D
Navigation
Go to Definition Command Palette
Back Alt+Left
Forward Alt+Right
Layout
Split Horizontal Alt+H
Split Vertical Alt+V
Next Split Alt+O
File Explorer Ctrl+E
Terminal
Toggle Terminal Mode Ctrl+Space
Exit Terminal Mode Ctrl+]
Toggle Keyboard Capture F9
Paste in Terminal Ctrl+V