Minimal Neovim + Flutter Setup (macOS)

Minimal Neovim + Flutter Setup (macOS)

Isolated. Beautiful. Fast. No Vim conflict.

Enhanced Neovim Setup for Flutter Development on macOS

Enhanced Neovim Setup for Flutter Development on macOS
Minimal setup: Minimal Neovim + Flutter Setup (macOS)Isolated. Beautiful. Fast. No Vim conflict.Mediumdanial Fine, danial, here’s your shiny, fully-updated final article. I stitched your latest config into the write-up so the whole thing feels clean and intentional. Try not to break it five minutes after publishing. Enhanced Neovim

NVIM_APPNAME=nvim-flutter forces Neovim to load only from ~/.config/nvim-flutter/. Your ~/.vimrc, ~/.vim/, and default ~/.config/nvim/ stay completely untouched — no shared plugins, paths, or side effects. vim and nvim run as before; nvimf is a safe, isolated Flutter IDE.NVIM_APPNAME=nvim-flutter forces Neovim to load only from ~/.config/nvim-flutter/. Your ~/.vimrc, ~/.vim/, and default ~/.config/nvim/ stay completely untouched — no shared plugins, paths, or side effects. vim and nvim run as before; nvimf is a safe, isolated Flutter IDE.

1. Install Neovim & Flutter

brew install neovim
brew install --cask flutter

2. Create Isolated Config

mkdir -p ~/.config/nvim-flutter

3. init.lua – Paste This (Clean & Final)

-- ~/.config/nvim-flutter/init.lua
vim.g.mapleader = " "

-- 1. Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git", "clone", "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    lazypath
  })
end
vim.opt.rtp:prepend(lazypath)

-- 2. Plugins
require("lazy").setup({
  { "neovim/nvim-lspconfig" },
  { "dart-lang/dart-vim-plugin" },
  { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate" },
  { "hrsh7th/nvim-cmp" },
  { "hrsh7th/cmp-nvim-lsp" },
  { "hrsh7th/cmp-buffer" },
  { "hrsh7th/cmp-path" },
  { "akinsho/flutter-tools.nvim", dependencies = { "nvim-lua/plenary.nvim" } },
  { "nvim-lualine/lualine.nvim" },
  { "lewis6991/gitsigns.nvim" },

  -- File Explorer + Icons
  {
    "nvim-tree/nvim-tree.lua",
    dependencies = { "nvim-tree/nvim-web-devicons" },
    config = function()
      require("nvim-tree").setup {
        view = { width = 35, side = "left" },
        renderer = {
          group_empty = true,
          icons = {
            glyphs = {
              folder = {
                arrow_closed = "▶",
                arrow_open = "▼",
              },
            },
          },
        },
        filters = { dotfiles = false },
        git = { enable = true, ignore = false },
      }
      vim.api.nvim_create_autocmd("VimEnter", {
        callback = function() vim.cmd("NvimTreeOpen") end
      })
    end,
  },
  { "ryanoasis/vim-devicons" },

  -- Colorscheme
  {
    "catppuccin/nvim",
    name = "catppuccin",
    priority = 1000,
    config = function()
      require("catppuccin").setup({
        flavour = "macchiato",
        integrations = {
          nvimtree = true,
          lsp = true,
          cmp = true,
          gitsigns = true,
          treesitter = true,
        },
      })
      vim.cmd.colorscheme "catppuccin"
    end
  },

  -- Lspsaga
  {
    "glepnir/lspsaga.nvim",
    event = "LspAttach",
    config = function()
      require("lspsaga").setup({
        lightbulb = { enable = false },
        symbol_in_winbar = { enable = false },
        hover = { max_width = 0.6, max_height = 0.6, open_link = "gO" },
        finder = { max_width = 0.6, max_height = 0.6 },
      })
    end,
  },
})

-- 3. Basic settings
vim.opt.number = true
vim.opt.signcolumn = "yes"
vim.opt.tabstop = 2
vim.opt.shiftwidth = 2
vim.opt.expandtab = true

-- 4. Treesitter
require("nvim-treesitter.configs").setup{
  ensure_installed = { "dart", "lua", "vim" },
  highlight = { enable = true },
}

-- 5. Completion
local cmp = require("cmp")
cmp.setup{
  sources = {
    { name = "nvim_lsp" },
    { name = "buffer" },
    { name = "path" },
  },
  mapping = cmp.mapping.preset.insert({
    ["<C-Space>"] = cmp.mapping.complete(),
    ["<CR>"] = cmp.mapping.confirm({ select = true }),
  }),
}

-- 6. Keymaps
vim.keymap.set("n", "<leader>fr", ":FlutterRun<CR>",       { desc = "Flutter Run" })
vim.keymap.set("n", "<leader>fd", ":FlutterDevices<CR>",   { desc = "Devices" })
vim.keymap.set("n", "<leader>fh", ":FlutterHotReload<CR>", { desc = "Hot Reload" })
vim.keymap.set("n", "<leader>fH", ":FlutterHotRestart<CR>", { desc = "Hot Restart" })
vim.keymap.set("n", "<leader>fq", ":FlutterQuit<CR>",      { desc = "Quit" })

vim.keymap.set("n", "<leader>e", ":NvimTreeToggle<CR>", { desc = "Toggle Explorer" })
vim.keymap.set("n", "<leader>o", ":NvimTreeFocus<CR>",  { desc = "Focus Explorer" })

vim.keymap.set("n", "K",  "<cmd>Lspsaga hover_doc<CR>",     { desc = "Hover doc" })
vim.keymap.set("n", "gd", "<cmd>Lspsaga goto_definition<CR>", { desc = "Go to definition" })
vim.keymap.set("n", "gp", "<cmd>Lspsaga peek_definition<CR>", { desc = "Peek definition" })

-- Close Lspsaga windows with q/Esc
vim.api.nvim_create_autocmd("FileType", {
  pattern = { "saga_hover", "saga_peek", "saga_finder", "sagaoutline" },
  callback = function()
    vim.keymap.set("n", "q", "<cmd>close<CR>", { buffer = true, silent = true })
    vim.keymap.set("n", "<Esc>", "<cmd>close<CR>", { buffer = true, silent = true })
  end,
})

4. Alias (Safe from vim)

echo "alias nvimf='NVIM_APPNAME=nvim-flutter nvim'" >> ~/.zshrc
source ~/.zshrc

5. Launch

nvimf
First run: plugins install.
Tree opens on left.
Hover with K, jump with gd, peek with gp.

Keybinds

Key Action
<leader>fr Run app
<leader>fh Hot reload
<leader>e Toggle tree
K Hover docs
gd Go to definition
gp Peek definition
q / Esc Close float

Done.
Your vim is untouched.
Flutter dev = fast, pretty, pro