Skip to content

pretodev/copy-widget.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

copy-widget.nvim

Select a Flutter widget and its entire child tree in Neovim.

Inspired by the copy-widget VS Code extension.

What it does

Place your cursor on any Flutter widget name (or inside its parentheses) and run the :CopyWidgetSelect command. The plugin will visually select the widget constructor call and every nested child within it. You can then copy, delete, cut, or perform any other Neovim operation on the selection.

MaterialApp(
  child: Scaffold(       // <- cursor here selects Scaffold and everything inside
    appBar: AppBar(
      title: Text('Hello'),
    ),
    body: Column(
      children: [
        Container(       // <- cursor here selects Container + its child Text
          child: Text('World'),
        ),
        ListView(),
      ],
    ),
  ),
)

Installation

{
  "pretodev/copy-widget.nvim",
  ft = "dart",
  config = true,
}
use {
  "pretodev/copy-widget.nvim",
  ft = "dart",
  config = function()
    require("copy-widget").setup()
  end,
}

Keymaps

The plugin does not define any default keymaps. Bind the command to whatever key you prefer:

vim.keymap.set("n", "<A-w>", "<cmd>CopyWidgetSelect<cr>", {
  desc = "Select Flutter widget",
})

Or inside the lazy.nvim spec:

{
  "pretodev/copy-widget.nvim",
  ft = "dart",
  config = true,
  keys = {
    { "<A-w>", "<cmd>CopyWidgetSelect<cr>", desc = "Select Flutter widget", ft = "dart" },
  },
}

Commands

Command Description
:CopyWidgetSelect Select the widget at cursor and its entire subtree

How it works

The plugin uses bracket matching on ( / ) pairs -- the same delimiters that Dart uses for constructor calls. When the command runs:

  1. If the cursor is on a widget name (an identifier followed by (), the plugin finds the matching ) and selects from the name through the closing paren.
  2. If the cursor is inside a widget's parentheses (on a property name, a string literal, whitespace, etc.), the plugin searches backward for the nearest unmatched (, identifies the widget name before it, and searches forward for the matching ).

This approach is simple, predictable, and requires no external dependencies (no Treesitter parser, no LSP).

Supported patterns:

  • Simple widgets: Text('hello')
  • Nested trees: Scaffold(body: Column(children: [...]))
  • Generic types: ListView<String>(children: [...])
  • Named constructors: Text.rich(TextSpan(...))
  • const / new keywords are excluded from the selection (only the widget itself is selected)

Running tests

Tests use plenary.nvim:

make test

If plenary is not in the default location, point to it:

PLENARY_PATH=/path/to/plenary.nvim make test

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors