Skip to content

pretodev/bloc.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bloc.nvim

Neovim plugin that accelerates Flutter Bloc/Cubit workflows. Generate files, update event handlers, wrap widgets, insert context accessors, and more -- all without leaving your editor.

Features

  • BlocCreate / CubitCreate -- Generate Bloc (3 files) or Cubit (2 files) scaffolds with equatable, freezed, or plain templates, auto-detected from pubspec.yaml
  • BlocUpdateEvents -- Scan event hierarchy and add missing on<Event> registrations + handler methods
  • Wrap with Bloc widgets -- Wrap any widget with BlocBuilder, BlocSelector, BlocListener, BlocConsumer, BlocProvider, or RepositoryProvider
  • Unwrap -- Remove a Bloc widget wrapper and extract the child
  • Convert to Multi* -- Convert nested BlocProvider/BlocListener/RepositoryProvider into their Multi* equivalents
  • BlocRead / BlocWatch / BlocSelect -- Insert context.read<T>(), context.watch<T>(), or context.select() with a type picker
  • Code Actions -- Context-aware action menu via :BlocCodeAction (with optional none-ls/null-ls integration)
  • Project scanning -- Discovers all Bloc/Cubit types in your project for picker UIs

Requirements

  • Neovim >= 0.9
  • A Flutter project with flutter_bloc / bloc in dependencies
  • plenary.nvim (for tests only)

No treesitter, LSP, or external binary dependencies required.

Installation

lazy.nvim

{
  "pretodev/bloc.nvim",
  ft = "dart",
  opts = {},
}

packer.nvim

use {
  "pretodev/bloc.nvim",
  config = function()
    require("bloc").setup()
  end,
}

Configuration

All options with their defaults:

require("bloc").setup({
  -- When both equatable and freezed are detected, prefer this style
  style_priority = "equatable", -- "equatable" | "freezed"

  -- Use Dart 3 sealed/final classes for events and states
  use_sealed_classes = true,

  -- Suffix for the initial state subclass
  state_suffix = "Initial",

  -- Enable none-ls/null-ls code action integration
  none_ls = false,

  -- Default keymaps (set individual keys to false to disable)
  keymaps = {},
})

Commands

Command Description
:BlocCreate[!] Name path Generate Bloc files (bloc + event + state). Use ! to overwrite existing files.
:CubitCreate[!] Name path Generate Cubit files (cubit + state). Use ! to overwrite.
:BlocUpdateEvents Add missing event handler registrations in the current Bloc class.
:BlocWrap Wrap widget at cursor with a Bloc widget (interactive picker).
:BlocUnwrap Unwrap Bloc widget at cursor, extracting the child.
:BlocConvert Convert nested Bloc widgets to Multi* variant.
:BlocRead Insert context.read<T>() at cursor with type picker.
:BlocWatch Insert context.watch<T>() at cursor with type picker.
:BlocSelect Insert context.select() at cursor with type picker.
:BlocCodeAction Show all available Bloc code actions at cursor.

Usage Examples

Create a Bloc

:BlocCreate Home lib/features/home/bloc

Creates three files in lib/features/home/bloc/:

  • home_bloc.dart
  • home_event.dart
  • home_state.dart

The template style (equatable/freezed/plain) is auto-detected from your pubspec.yaml.

Update Event Handlers

Place your cursor inside a Bloc class body and run:

:BlocUpdateEvents

The plugin reads the event file, finds all concrete event subclasses, and adds missing on<Event> registrations and handler method stubs.

Wrap a Widget

Place your cursor on a widget and run:

:BlocWrap

Select the wrapper type (e.g., BlocBuilder) and the Bloc/Cubit type from pickers. The widget is wrapped in-place.

Convert Nested Providers

When you have nested BlocProvider widgets:

BlocProvider<HomeBloc>(
  create: (context) => HomeBloc(),
  child: BlocProvider<AuthBloc>(
    create: (context) => AuthBloc(),
    child: AppView(),
  ),
)

Place your cursor on the outer BlocProvider and run:

:BlocConvert

It becomes:

MultiBlocProvider(
  providers: [
    BlocProvider<HomeBloc>(
      create: (context) => HomeBloc(),
    ),
    BlocProvider<AuthBloc>(
      create: (context) => AuthBloc(),
    ),
  ],
  child: AppView(),
)

Code Actions

Run :BlocCodeAction on any widget or Bloc class to see context-aware actions:

  • Inside a Bloc class with missing event handlers: "Update Event Handlers (N missing)"
  • On any widget: wrap/unwrap options
  • On nested providers/listeners: convert to Multi* variant

none-ls Integration

Enable in setup to surface code actions through your LSP code action menu:

require("bloc").setup({
  none_ls = true,
})

Requires none-ls.nvim to be installed.

Programmatic API

All functionality is accessible programmatically:

local bloc = require("bloc")

bloc.create_bloc("Home", "lib/features/home/bloc", { style = "equatable" })
bloc.create_cubit("Counter", "lib/counter", { style = "plain", force = true })
bloc.update_events()
bloc.wrap()
bloc.unwrap()
bloc.convert()
bloc.bloc_read()
bloc.bloc_watch()
bloc.bloc_select()
bloc.code_action()

How It Works

  • No treesitter dependency -- Uses regex and bracket-counting parsing for reliable Dart code analysis
  • Project scanning -- Reads pubspec.yaml to detect dependencies and scans lib/ for Bloc/Cubit classes
  • Style auto-detection -- When both equatable and freezed are present, style_priority config controls which template is used
  • Safe by default -- Won't overwrite existing files without ! bang, won't duplicate event registrations

Testing

Tests use plenary.nvim busted-style specs.

# Run all tests
make test

# Run a single test file
make test-file FILE=tests/bloc/parser_spec.lua

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors