Skip to main content
The Status and Logging API provides methods for communicating with users through status messages and logging plugin activity for debugging and monitoring.

Status Messages

setStatus

Display a transient message in the editor’s status bar.
setStatus(message: string): void
message
string
required
Text to display (keep short - status bar has limited width)
The message will be shown until the next status update or user action. Use for feedback on completed operations (e.g., “File saved”, “2 matches found”).
Example:
// Simple status message
editor.setStatus("File saved successfully");

// Status with dynamic content
const count = results.length;
editor.setStatus(`Found ${count} matches`);

// Status after operation
await editor.spawnProcess("git", ["pull"]);
editor.setStatus("Git pull completed");

Logging Functions

Fresh provides four log levels for plugin messages. Messages appear in the log file when running with appropriate RUST_LOG environment variable settings.

debug

Log a debug message from a plugin.
debug(message: string): void
message
string
required
Debug message - include context like function name and relevant values
Messages appear in log file when running with RUST_LOG=debug. Useful for plugin development and troubleshooting.
Example:
editor.debug(`Search query: "${query}", found ${results.length} results`);
editor.debug(`Buffer ID: ${bufferId}, cursor at ${position}`);

info

Log an info message from a plugin.
info(message: string): void
message
string
required
Info message
Messages appear in log file when running with RUST_LOG=info. Use for important operational messages.
Example:
editor.info("Plugin initialized successfully");
editor.info(`Loaded configuration from ${configPath}`);

warn

Log a warning message from a plugin.
warn(message: string): void
message
string
required
Warning message
Messages appear in log file when running with RUST_LOG=warn. Use for warnings that don’t prevent operation but indicate issues.
Example:
editor.warn("Config file not found, using defaults");
editor.warn(`Git command failed: ${stderr}`);

error

Log an error message from a plugin.
error(message: string): void
message
string
required
Error message
Messages appear in log file when running with RUST_LOG=error. Use for critical errors that need attention.
Example:
editor.error("Failed to initialize LSP server");
editor.error(`Unable to read file: ${error}`);

Log Levels

Control which messages appear in the log by setting the RUST_LOG environment variable:
# Show all messages (debug, info, warn, error)
RUST_LOG=debug fresh

Best Practices

  • debug(): Development info, variable values, function entry/exit
  • info(): Important milestones, configuration loaded, plugin initialized
  • warn(): Recoverable issues, missing config, deprecated features
  • error(): Critical failures, exceptions, data corruption
Make log messages self-explanatory by including relevant context:
// Bad
editor.debug("Processing");

// Good
editor.debug(`Processing ${files.length} files from ${directory}`);
Status messages are for users, log messages are for developers:
// User sees this
editor.setStatus("Search completed");

// Developer sees this in logs
editor.info(`Search found ${results.length} matches in ${elapsed}ms`);
The status bar has limited width. Keep messages short and clear:
// Good
editor.setStatus("Saved");
editor.setStatus("3 errors, 2 warnings");

// Too long
editor.setStatus("File has been successfully saved to disk at /very/long/path/...");

Examples

Progress indication

async function processFiles(files: string[]) {
  editor.info(`Processing ${files.length} files`);
  
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    editor.setStatus(`Processing ${i + 1}/${files.length}: ${file}`);
    editor.debug(`Processing file: ${file}`);
    
    try {
      await processFile(file);
    } catch (error) {
      editor.error(`Failed to process ${file}: ${error}`);
    }
  }
  
  editor.setStatus(`Processed ${files.length} files`);
  editor.info("Processing complete");
}

Error handling with logging

async function loadConfig() {
  const configPath = editor.pathJoin([editor.getConfigDir(), "my-plugin.json"]);
  
  if (!editor.fileExists(configPath)) {
    editor.warn(`Config file not found at ${configPath}, using defaults`);
    return getDefaultConfig();
  }
  
  try {
    const content = await editor.readFile(configPath);
    const config = JSON.parse(content);
    editor.info(`Loaded config from ${configPath}`);
    return config;
  } catch (error) {
    editor.error(`Failed to load config: ${error}`);
    editor.setStatus("Failed to load config, using defaults");
    return getDefaultConfig();
  }
}

Debug logging for troubleshooting

function findReferences(symbol: string) {
  editor.debug(`findReferences called with symbol: "${symbol}"`);
  
  const bufferId = editor.getActiveBufferId();
  const path = editor.getBufferPath(bufferId);
  editor.debug(`Current buffer: ${bufferId}, path: ${path}`);
  
  const cursor = editor.getPrimaryCursor();
  editor.debug(`Cursor position: ${cursor?.position}, selection: ${JSON.stringify(cursor?.selection)}`);
  
  // ... find references logic ...
  
  editor.debug(`Found ${references.length} references`);
  return references;
}

Combining status and logging

async function runLinter() {
  editor.info("Starting linter");
  editor.setStatus("Running linter...");
  
  try {
    const result = await editor.spawnProcess("eslint", ["."]);
    
    if (result.exit_code === 0) {
      editor.info("Linter completed with no errors");
      editor.setStatus("No lint errors");
    } else {
      const errorCount = result.stdout.split("\n").length;
      editor.warn(`Linter found ${errorCount} issues`);
      editor.setStatus(`${errorCount} lint errors`);
    }
  } catch (error) {
    editor.error(`Linter failed: ${error}`);
    editor.setStatus("Linter failed");
  }
}

Build docs developers (and LLMs) love