Code Monkey home page Code Monkey logo

aerial.nvim's Introduction

aerial.nvim

A code outline window for skimming and quick navigation

aerial.mp4

Requirements

Installation

aerial supports all the usual plugin managers

lazy.nvim
{
  'stevearc/aerial.nvim',
  opts = {},
  -- Optional dependencies
  dependencies = {
     "nvim-treesitter/nvim-treesitter",
     "nvim-tree/nvim-web-devicons"
  },
}
Packer
require("packer").startup(function()
  use({
    "stevearc/aerial.nvim",
    config = function()
      require("aerial").setup()
    end,
  })
end)
Paq
require("paq")({
  { "stevearc/aerial.nvim" },
})
vim-plug
Plug 'stevearc/aerial.nvim'
dein
call dein#add('stevearc/aerial.nvim')
Pathogen
git clone --depth=1 https://github.com/stevearc/aerial.nvim.git ~/.vim/bundle/
Neovim native package
git clone --depth=1 https://github.com/stevearc/aerial.nvim.git \
  "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/pack/aerial/start/aerial.nvim

Setup

Somewhere in your init.lua you will need to call aerial.setup(). See below for a full list of options.

require("aerial").setup({
  -- optionally use on_attach to set keymaps when aerial has attached to a buffer
  on_attach = function(bufnr)
    -- Jump forwards/backwards with '{' and '}'
    vim.keymap.set("n", "{", "<cmd>AerialPrev<CR>", { buffer = bufnr })
    vim.keymap.set("n", "}", "<cmd>AerialNext<CR>", { buffer = bufnr })
  end,
})
-- You probably also want to set a keymap to toggle aerial
vim.keymap.set("n", "<leader>a", "<cmd>AerialToggle!<CR>")

In addition, you will need to have either Treesitter or a working LSP client. You can configure your preferred source(s) with the backends option (see Options). The default is to prefer Treesitter when it's available and fall back to LSP.

Supported treesitter languages
  • bash
  • c
  • c_sharp
  • cpp
  • dart
  • elixir
  • go
  • groovy
  • help
  • html
  • java
  • javascript
  • json
  • julia
  • latex
  • lua
  • make
  • markdown
  • norg
  • objdump
  • org
  • php
  • proto
  • python
  • rst
  • ruby
  • rust
  • scala
  • snakemake
  • solidity
  • teal
  • tsx
  • typescript
  • usd
  • vim
  • vimdoc
  • yaml
  • zig

Don't see your language here? Request support for it

Commands

Command Args Description
AerialToggle[!] left/right/float Open or close the aerial window. With ! cursor stays in current window
AerialOpen[!] left/right/float Open the aerial window. With ! cursor stays in current window
AerialOpenAll Open an aerial window for each visible window.
AerialClose Close the aerial window.
AerialCloseAll Close all visible aerial windows.
[count]AerialNext Jump forwards {count} symbols (default 1).
[count]AerialPrev Jump backwards [count] symbols (default 1).
[count]AerialGo[!] Jump to the [count] symbol (default 1).
AerialInfo Print out debug info related to aerial.
AerialNavToggle Open or close the aerial nav window.
AerialNavOpen Open the aerial nav window.
AerialNavClose Close the aerial nav window.

Options

-- Call the setup function to change the default behavior
require("aerial").setup({
  -- Priority list of preferred backends for aerial.
  -- This can be a filetype map (see :help aerial-filetype-map)
  backends = { "treesitter", "lsp", "markdown", "asciidoc", "man" },

  layout = {
    -- These control the width of the aerial window.
    -- They can be integers or a float between 0 and 1 (e.g. 0.4 for 40%)
    -- min_width and max_width can be a list of mixed types.
    -- max_width = {40, 0.2} means "the lesser of 40 columns or 20% of total"
    max_width = { 40, 0.2 },
    width = nil,
    min_width = 10,

    -- key-value pairs of window-local options for aerial window (e.g. winhl)
    win_opts = {},

    -- Determines the default direction to open the aerial window. The 'prefer'
    -- options will open the window in the other direction *if* there is a
    -- different buffer in the way of the preferred direction
    -- Enum: prefer_right, prefer_left, right, left, float
    default_direction = "prefer_right",

    -- Determines where the aerial window will be opened
    --   edge   - open aerial at the far right/left of the editor
    --   window - open aerial to the right/left of the current window
    placement = "window",

    -- When the symbols change, resize the aerial window (within min/max constraints) to fit
    resize_to_content = true,

    -- Preserve window size equality with (:help CTRL-W_=)
    preserve_equality = false,
  },

  -- Determines how the aerial window decides which buffer to display symbols for
  --   window - aerial window will display symbols for the buffer in the window from which it was opened
  --   global - aerial window will display symbols for the current window
  attach_mode = "window",

  -- List of enum values that configure when to auto-close the aerial window
  --   unfocus       - close aerial when you leave the original source window
  --   switch_buffer - close aerial when you change buffers in the source window
  --   unsupported   - close aerial when attaching to a buffer that has no symbol source
  close_automatic_events = {},

  -- Keymaps in aerial window. Can be any value that `vim.keymap.set` accepts OR a table of keymap
  -- options with a `callback` (e.g. { callback = function() ... end, desc = "", nowait = true })
  -- Additionally, if it is a string that matches "actions.<name>",
  -- it will use the mapping at require("aerial.actions").<name>
  -- Set to `false` to remove a keymap
  keymaps = {
    ["?"] = "actions.show_help",
    ["g?"] = "actions.show_help",
    ["<CR>"] = "actions.jump",
    ["<2-LeftMouse>"] = "actions.jump",
    ["<C-v>"] = "actions.jump_vsplit",
    ["<C-s>"] = "actions.jump_split",
    ["p"] = "actions.scroll",
    ["<C-j>"] = "actions.down_and_scroll",
    ["<C-k>"] = "actions.up_and_scroll",
    ["{"] = "actions.prev",
    ["}"] = "actions.next",
    ["[["] = "actions.prev_up",
    ["]]"] = "actions.next_up",
    ["q"] = "actions.close",
    ["o"] = "actions.tree_toggle",
    ["za"] = "actions.tree_toggle",
    ["O"] = "actions.tree_toggle_recursive",
    ["zA"] = "actions.tree_toggle_recursive",
    ["l"] = "actions.tree_open",
    ["zo"] = "actions.tree_open",
    ["L"] = "actions.tree_open_recursive",
    ["zO"] = "actions.tree_open_recursive",
    ["h"] = "actions.tree_close",
    ["zc"] = "actions.tree_close",
    ["H"] = "actions.tree_close_recursive",
    ["zC"] = "actions.tree_close_recursive",
    ["zr"] = "actions.tree_increase_fold_level",
    ["zR"] = "actions.tree_open_all",
    ["zm"] = "actions.tree_decrease_fold_level",
    ["zM"] = "actions.tree_close_all",
    ["zx"] = "actions.tree_sync_folds",
    ["zX"] = "actions.tree_sync_folds",
  },

  -- When true, don't load aerial until a command or function is called
  -- Defaults to true, unless `on_attach` is provided, then it defaults to false
  lazy_load = true,

  -- Disable aerial on files with this many lines
  disable_max_lines = 10000,

  -- Disable aerial on files this size or larger (in bytes)
  disable_max_size = 2000000, -- Default 2MB

  -- A list of all symbols to display. Set to false to display all symbols.
  -- This can be a filetype map (see :help aerial-filetype-map)
  -- To see all available values, see :help SymbolKind
  filter_kind = {
    "Class",
    "Constructor",
    "Enum",
    "Function",
    "Interface",
    "Module",
    "Method",
    "Struct",
  },

  -- Determines line highlighting mode when multiple splits are visible.
  -- split_width   Each open window will have its cursor location marked in the
  --               aerial buffer. Each line will only be partially highlighted
  --               to indicate which window is at that location.
  -- full_width    Each open window will have its cursor location marked as a
  --               full-width highlight in the aerial buffer.
  -- last          Only the most-recently focused window will have its location
  --               marked in the aerial buffer.
  -- none          Do not show the cursor locations in the aerial window.
  highlight_mode = "split_width",

  -- Highlight the closest symbol if the cursor is not exactly on one.
  highlight_closest = true,

  -- Highlight the symbol in the source buffer when cursor is in the aerial win
  highlight_on_hover = false,

  -- When jumping to a symbol, highlight the line for this many ms.
  -- Set to false to disable
  highlight_on_jump = 300,

  -- Jump to symbol in source window when the cursor moves
  autojump = false,

  -- Define symbol icons. You can also specify "<Symbol>Collapsed" to change the
  -- icon when the tree is collapsed at that symbol, or "Collapsed" to specify a
  -- default collapsed icon. The default icon set is determined by the
  -- "nerd_font" option below.
  -- If you have lspkind-nvim installed, it will be the default icon set.
  -- This can be a filetype map (see :help aerial-filetype-map)
  icons = {},

  -- Control which windows and buffers aerial should ignore.
  -- Aerial will not open when these are focused, and existing aerial windows will not be updated
  ignore = {
    -- Ignore unlisted buffers. See :help buflisted
    unlisted_buffers = false,

    -- Ignore diff windows (setting to false will allow aerial in diff windows)
    diff_windows = true,

    -- List of filetypes to ignore.
    filetypes = {},

    -- Ignored buftypes.
    -- Can be one of the following:
    -- false or nil - No buftypes are ignored.
    -- "special"    - All buffers other than normal, help and man page buffers are ignored.
    -- table        - A list of buftypes to ignore. See :help buftype for the
    --                possible values.
    -- function     - A function that returns true if the buffer should be
    --                ignored or false if it should not be ignored.
    --                Takes two arguments, `bufnr` and `buftype`.
    buftypes = "special",

    -- Ignored wintypes.
    -- Can be one of the following:
    -- false or nil - No wintypes are ignored.
    -- "special"    - All windows other than normal windows are ignored.
    -- table        - A list of wintypes to ignore. See :help win_gettype() for the
    --                possible values.
    -- function     - A function that returns true if the window should be
    --                ignored or false if it should not be ignored.
    --                Takes two arguments, `winid` and `wintype`.
    wintypes = "special",
  },

  -- Use symbol tree for folding. Set to true or false to enable/disable
  -- Set to "auto" to manage folds if your previous foldmethod was 'manual'
  -- This can be a filetype map (see :help aerial-filetype-map)
  manage_folds = false,

  -- When you fold code with za, zo, or zc, update the aerial tree as well.
  -- Only works when manage_folds = true
  link_folds_to_tree = false,

  -- Fold code when you open/collapse symbols in the tree.
  -- Only works when manage_folds = true
  link_tree_to_folds = true,

  -- Set default symbol icons to use patched font icons (see https://www.nerdfonts.com/)
  -- "auto" will set it to true if nvim-web-devicons or lspkind-nvim is installed.
  nerd_font = "auto",

  -- Call this function when aerial attaches to a buffer.
  on_attach = function(bufnr) end,

  -- Call this function when aerial first sets symbols on a buffer.
  on_first_symbols = function(bufnr) end,

  -- Automatically open aerial when entering supported buffers.
  -- This can be a function (see :help aerial-open-automatic)
  open_automatic = false,

  -- Run this command after jumping to a symbol (false will disable)
  post_jump_cmd = "normal! zz",

  -- Invoked after each symbol is parsed, can be used to modify the parsed item,
  -- or to filter it by returning false.
  --
  -- bufnr: a neovim buffer number
  -- item: of type aerial.Symbol
  -- ctx: a record containing the following fields:
  --   * backend_name: treesitter, lsp, man...
  --   * lang: info about the language
  --   * symbols?: specific to the lsp backend
  --   * symbol?: specific to the lsp backend
  --   * syntax_tree?: specific to the treesitter backend
  --   * match?: specific to the treesitter backend, TS query match
  post_parse_symbol = function(bufnr, item, ctx)
    return true
  end,

  -- Invoked after all symbols have been parsed and post-processed,
  -- allows to modify the symbol structure before final display
  --
  -- bufnr: a neovim buffer number
  -- items: a collection of aerial.Symbol items, organized in a tree,
  --        with 'parent' and 'children' fields
  -- ctx: a record containing the following fields:
  --   * backend_name: treesitter, lsp, man...
  --   * lang: info about the language
  --   * symbols?: specific to the lsp backend
  --   * syntax_tree?: specific to the treesitter backend
  post_add_all_symbols = function(bufnr, items, ctx)
    return items
  end,

  -- When true, aerial will automatically close after jumping to a symbol
  close_on_select = false,

  -- The autocmds that trigger symbols update (not used for LSP backend)
  update_events = "TextChanged,InsertLeave",

  -- Show box drawing characters for the tree hierarchy
  show_guides = false,

  -- Customize the characters used when show_guides = true
  guides = {
    -- When the child item has a sibling below it
    mid_item = "├─",
    -- When the child item is the last in the list
    last_item = "└─",
    -- When there are nested child guides to the right
    nested_top = "",
    -- Raw indentation
    whitespace = "  ",
  },

  -- Set this function to override the highlight groups for certain symbols
  get_highlight = function(symbol, is_icon, is_collapsed)
    -- return "MyHighlight" .. symbol.kind
  end,

  -- Options for opening aerial in a floating win
  float = {
    -- Controls border appearance. Passed to nvim_open_win
    border = "rounded",

    -- Determines location of floating window
    --   cursor - Opens float on top of the cursor
    --   editor - Opens float centered in the editor
    --   win    - Opens float centered in the window
    relative = "cursor",

    -- These control the height of the floating window.
    -- They can be integers or a float between 0 and 1 (e.g. 0.4 for 40%)
    -- min_height and max_height can be a list of mixed types.
    -- min_height = {8, 0.1} means "the greater of 8 rows or 10% of total"
    max_height = 0.9,
    height = nil,
    min_height = { 8, 0.1 },

    override = function(conf, source_winid)
      -- This is the config that will be passed to nvim_open_win.
      -- Change values here to customize the layout
      return conf
    end,
  },

  -- Options for the floating nav windows
  nav = {
    border = "rounded",
    max_height = 0.9,
    min_height = { 10, 0.1 },
    max_width = 0.5,
    min_width = { 0.2, 20 },
    win_opts = {
      cursorline = true,
      winblend = 10,
    },
    -- Jump to symbol in source window when the cursor moves
    autojump = false,
    -- Show a preview of the code in the right column, when there are no child symbols
    preview = false,
    -- Keymaps in the nav window
    keymaps = {
      ["<CR>"] = "actions.jump",
      ["<2-LeftMouse>"] = "actions.jump",
      ["<C-v>"] = "actions.jump_vsplit",
      ["<C-s>"] = "actions.jump_split",
      ["h"] = "actions.left",
      ["l"] = "actions.right",
      ["<C-c>"] = "actions.close",
    },
  },

  lsp = {
    -- If true, fetch document symbols when LSP diagnostics update.
    diagnostics_trigger_update = false,

    -- Set to false to not update the symbols when there are LSP errors
    update_when_errors = true,

    -- How long to wait (in ms) after a buffer change before updating
    -- Only used when diagnostics_trigger_update = false
    update_delay = 300,

    -- Map of LSP client name to priority. Default value is 10.
    -- Clients with higher (larger) priority will be used before those with lower priority.
    -- Set to -1 to never use the client.
    priority = {
      -- pyright = 10,
    },
  },

  treesitter = {
    -- How long to wait (in ms) after a buffer change before updating
    update_delay = 300,
  },

  markdown = {
    -- How long to wait (in ms) after a buffer change before updating
    update_delay = 300,
  },

  asciidoc = {
    -- How long to wait (in ms) after a buffer change before updating
    update_delay = 300,
  },

  man = {
    -- How long to wait (in ms) after a buffer change before updating
    update_delay = 300,
  },
})

All possible SymbolKind values can be found in the LSP spec. These are the values used for configuring icons, highlight groups, and filtering.

The aerial.Symbol type used in some optional callbacks is:

{
kind: SymbolKind,
name: string,
level: number,
parent: aerial.Symbol,
lnum: number,
end_lnum: number,
col: number,
end_col: number
}

Third-party integrations

Telescope

If you have telescope installed, there is an extension for fuzzy finding and jumping to symbols. It functions similarly to the builtin lsp_document_symbols picker, the main difference being that it uses the aerial backend for the source (e.g. LSP, treesitter, etc) and that it filters out some symbols (see the filter_kind option).

You can activate the picker with :Telescope aerial or :lua require("telescope").extensions.aerial.aerial()

If you want the command to autocomplete, you can load the extension first:

require("telescope").load_extension("aerial")

The extension can be customized with the following options:

require("telescope").setup({
  extensions = {
    aerial = {
      -- Display symbols as <root>.<parent>.<symbol>
      show_nesting = {
        ["_"] = false, -- This key will be the default
        json = true, -- You can set the option for specific filetypes
        yaml = true,
      },
    },
  },
})

fzf

If you have fzf installed you can trigger fuzzy finding with :call aerial#fzf(). To create a mapping:

nmap <silent> <leader>ds <cmd>call aerial#fzf()<cr>

Lualine

There is a lualine component to display the symbols for your current cursor position

require("lualine").setup({
  sections = {
    lualine_x = { "aerial" },

    -- Or you can customize it
    lualine_y = {
      {
        "aerial",
        -- The separator to be used to separate symbols in status line.
        sep = " ) ",

        -- The number of symbols to render top-down. In order to render only 'N' last
        -- symbols, negative numbers may be supplied. For instance, 'depth = -1' can
        -- be used in order to render only current symbol.
        depth = nil,

        -- When 'dense' mode is on, icons are not rendered near their symbols. Only
        -- a single icon that represents the kind of current symbol is rendered at
        -- the beginning of status line.
        dense = false,

        -- The separator to be used to separate symbols in dense mode.
        dense_sep = ".",

        -- Color the symbol icons.
        colored = true,
      },
    },
  },
})

Highlight

There are highlight groups created for each SymbolKind. There will be one for the name of the symbol (Aerial<SymbolKind>, and one for the icon (Aerial<SymbolKind>Icon). For example:

hi link AerialClass Type
hi link AerialClassIcon Special
hi link AerialFunction Special
hi AerialFunctionIcon guifg=#cb4b16 guibg=NONE guisp=NONE gui=NONE cterm=NONE

" There's also this group for the fallback of the text if a specific
" class highlight isn't defined
hi link AerialNormal Normal
" There's also this group for the cursor position
hi link AerialLine QuickFixLine
" If highlight_mode="split_width", you can set a separate color for the
" non-current location highlight
hi AerialLineNC guibg=Gray

" You can customize the guides (if show_guide=true)
hi link AerialGuide Comment
" You can set a different guide color for each level
hi AerialGuide1 guifg=Red
hi AerialGuide2 guifg=Blue

API

TreeSitter queries

When writing queries, the following captures and metadata are used by Aerial:

  • @symbol - required capture for the logical region being captured

  • kind - required metadata, a string value matching one of vim.lsp.protocol.SymbolKind

  • @name - capture to extract a name from its text

  • @start - a start of the match, influences matching of cursor position to aerial tree, defaults to @symbol

  • @end - an end of the match, influences matching of cursor position to aerial tree, defaults to @start

  • @selection - position to jump to when using Aerial for navigation, falls back to @name and @symbol

  • @scope - a node naming a scope for the match, its text is used to generate a custom "Comment" linked highlight for the entry, with exception of "public"

    A @scope node with text "developers" will result in its entry in the tree having an "AerialDevelopers" highlight applied to it.

  • scope - a metadata value serving the same role as @scope capture, overriding aforementioned capture

Note: a capture's text can be set or modified with #set! and #gsub! respectively.

FAQ

Q: I accidentally opened a file into the aerial window and it looks bad. How can I prevent this from happening?

Try installing stickybuf. It was designed to prevent exactly this problem.

aerial.nvim's People

Contributors

b0o avatar barklan avatar brunnseb avatar colinkennedy avatar daler avatar eddiebergman avatar emmanueltouzery avatar eric-song-nop avatar flavono123 avatar fnix2 avatar folke avatar genesistms avatar github-actions[bot] avatar jeremywells227 avatar linusboehm avatar madlabman avatar magidc avatar mehalter avatar monaqa avatar mpasa avatar ouuan avatar slotos avatar stevearc avatar ten3roberts avatar tersetears avatar threedaymonk avatar tomtomjhj avatar toupeira avatar wieerd avatar xxiaoa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

aerial.nvim's Issues

Global Aerial window

When using many splits, especially with open_automatic enabled, it can easily become very cluttered and take up much space when each split has its own Aerial window.

Would it be possible to have one Aerial window on the very left or right that displays the current splits symbols, rather than one per split. I'm not intending this to be default behaviour, but maybe an option.

[Ruby] "Number is not integral" error in RSpec file

Describe the bug
Triggering AerialToggle on a Ruby RSpec file causes an error in aerial/util.lua:

E5108: Error executing lua ...vim/site/pack/packer/opt/aerial.nvim/lua/aerial/util.lua:54: Number is not integral stack traceback:
        [C]: in function 'nvim_win_set_width'
        ...vim/site/pack/packer/opt/aerial.nvim/lua/aerial/util.lua:54: in function 'set_win_width'
        ...m/site/pack/packer/opt/aerial.nvim/lua/aerial/window.lua:107: in function 'create_aerial_window'
        ...m/site/pack/packer/opt/aerial.nvim/lua/aerial/window.lua:168: in function 'open'
        ...m/site/pack/packer/opt/aerial.nvim/lua/aerial/window.lua:200: in function 'toggle'
        [string "luaeval()"]:1: in main chunk

System information

  • OS: macOS 12.1
  • Neovim version: 0.6.0
  • AerialInfo:
Filetype: ruby
Configured backends:
  lsp (not supported)
  treesitter (supported) (attached)
  markdown (not supported)
Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct

To Reproduce
Steps to reproduce the behavior:

  1. Open the following file, zeitwork_spec.rb in Neovim, with aerial.nvim installed:
describe "Zeitwerk" do
  it "eager loads all files" do
    expect { Zeitwerk::Loader.eager_load_all }.not_to raise_error
  end
end
  1. Run AerialToggle

Other Points to Note
aerial.nvim works perfectly on other Ruby files, such as:

class MyController < ActionController::API
  def index; end

  def create; end

  def show; end
end

and produces the following output:
Screen Shot 2021-12-29 at 12 22 48@2x

Error when using Sorbet

When using this plugin with Sorbet (Ruby language server) I get the following.

Error executing vim.schedule lua callback: /usr/local/share/nvim/runtime/lua/vim/lsp/diagnostic.lua:1091: Vim(lua):E5108: Error executing lua vim/shared.lua:200: Expected table, got number  

The error message is a bit misleading, but when I add if type(t) == 'number' then print(vim.inspect(debug.getinfo(2, 'nS'))) end at the top of vim.tbl_isempty in Neovim source code I get:

{                                                                                                                                                                                                                 
  lastlinedefined = 93,                                                                                                                                                                                           
  linedefined = 75,                                                                                                                                                                                               
  name = "handler",                                                                                                                                                                                               
  namewhat = "local",                                                                                                                                                                                             
  short_src = "...e/pack/backpack/opt/aerial.nvim/lua/aerial/callbacks.lua",                                                                                                                                      
  source = "@/Users/adam.regaszrethy/.local/share/nvim/site/pack/backpack/opt/aerial.nvim/lua/aerial/callbacks.lua",                                                                                              
  what = "Lua"                                                                                                                                                                                                    
} 

This is essentially the stack frame above vim.tbl_isempty's stack frame. A partly related note, you should be using client.supports_method('textDocument/documentSymbol') to check server capabilities.

Not playing well with rmagatti/goto-preview

Describe the bug
I initially reported it with goto-preview, but rmagatti was thinking maybe its due to aerial ...

System information

  • OS: [windows/linux/mac] mac
  • Neovim version:0.7 nightly (v0.7.0-dev+2267-gc46f7caad)
  • AerialInfo: [output of :AerialInfo]
    Aerial Info

Filetype: typescriptreact
Configured backends:
lsp (supported) (attached)
treesitter (not supported)
Show symbols: all symbols

To Reproduce
Steps to reproduce the behavior:

  1. install goto-preview alongside aerial (or use my setup github.com/joehannes-os/neovim-lua-setup
  2. use default goto-preview shortcut to preview definition of a thing in a floating window "gpd" in normal mode with cursor on the thing (eg.: a React Component var ... but not the definition, haha)
  3. see it fail with an aerial error msg

If possible, provide a minimal file that will trigger the issue:

sorry ...

Screenshots
8089FD12-9F1F-45C4-96A1-CC9A56702B78

Additional context
Add any other context about the problem here.

Feature - show parent class(es)

Hi would it be possible to show parent classes in aerial?
image
IMO it could help navigate code faster if we could in addition use to jump into parent definition

Add option for open aerial in floating window

I wish aerial could open in floating window - somewhere close to current cursor position.
This way user eyes wont have to travel so far away from current coding position.
From this:
image

to somthing like this:
image

[help] No LSP clients support textDocument/documentSymbol

hey, very nice plugin.
i have neovim 0.6 and this plugin (https://github.com/neovim/nvim-lspconfig) installed.

i pasted

lua << EOF
local aerial = require'aerial'

local custom_attach = function(client)
  aerial.on_attach(client)

  -- Aerial does not set any mappings by default, so you'll want to set some up
  -- Toggle the aerial window with <leader>a
  vim.api.nvim_buf_set_keymap(0, 'n', '<leader>a', '<cmd>AerialToggle!<CR>', {})
  -- Jump forwards/backwards with '{' and '}'
  vim.api.nvim_buf_set_keymap(0, 'n', '{', '<cmd>AerialPrev<CR>', {})
  vim.api.nvim_buf_set_keymap(0, 'n', '}', '<cmd>AerialNext<CR>', {})
  -- Jump up the tree with '[[' or ']]'
  vim.api.nvim_buf_set_keymap(0, 'n', '[[', '<cmd>AerialPrevUp<CR>', {})
  vim.api.nvim_buf_set_keymap(0, 'n', ']]', '<cmd>AerialNextUp<CR>', {})

  -- This is a great place to set up all your other LSP mappings
end

-- Set up your LSP clients here, using the custom on_attach method
require'lspconfig'.vimls.setup{
  on_attach = custom_attach,
}
EOF

in my init.vim

when im trying to run AerialToggle! i get No LSP clients support textDocument/documentSymbol.

what am i missing?

im new to neovim and lua configurations. can someone please guide me to run this plugin successfully?

Cannot open aerial. No LSP clients support documentSymbol

I ran into this while trying to use aerial with python and I'm not sure how to go about debugging it. I made sure to call aerial.on_attach() when my lsp server was started.

:LspInfo reads:

Configured servers: efm, pyright, lua, python, rust
Neovim logs at: /home/devneal/.cache/nvim/lsp.log

2 client(s) attached to this buffer: efm, pyright

  Client: efm (id 5)
  	root:      /home/devneal/github/manim
  	filetypes: python
  	cmd:       /home/devneal/.local/share/nvim/lspinstall/efm/efm-langserver
  	


  Client: pyright (id 6)
  	root:      /home/devneal/github/manim
  	filetypes: python
  	cmd:       /home/devneal/.local/share/nvim/lspinstall/python/node_modules/.bin/pyright-langserver --stdio
  	


2 active client(s): 

  Client: efm (id 5)
  	root:      /home/devneal/github/manim
  	filetypes: python
  	cmd:       /home/devneal/.local/share/nvim/lspinstall/efm/efm-langserver
  	


  Client: pyright (id 6)
  	root:      /home/devneal/github/manim
  	filetypes: python
  	cmd:       /home/devneal/.local/share/nvim/lspinstall/python/node_modules/.bin/pyright-langserver --stdio

Performance issues with large files

Describe the bug
When I open a massive .bib file (62k lines), aerial produces quite noticeable lag. In fact, the editor hangs completely for a couple of seconds at a time.

The lag goes away when I comment out aerial (and keep everything else in my setup).

Is there any way to improve the performance of aerial.nvim, or at least disable it beyond certain file sizes?

System information

  • OS: linux
  • Neovim version: 0.6.0
  • AerialInfo:
Aerial Info
-----------
Filetype: bib
Configured backends:
  lsp (supported) (attached)
  treesitter (not supported)
  markdown (not supported)
Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct

To Reproduce
Steps to reproduce the behavior:

  1. Load a large .bib file
  2. Try to navigate around

Unfortunately, I cannot provide this .bib file since it belongs to my colleague.

Additional context

When Vim hangs, I noticed that sometimes when I mashed <C-c>, it would report that it was interrupted in the middle of Aerial's fold functions. While investigating that, I noticed that Aerial seems to conflict with FastFold when it comes to figuring out whether it should manage folds. I have manage_folds set to'auto', and even when I explicitly set foldmethod=syntax in my bib.vim, Aerial still tries to take over, because it saw that FastFold had set the foldmethod to manual (I verified this by running vim.cmd [[verbose set foldmethod]] in fold.lua.

However, even with manage_folds disabled entirely, I'm still seeing really bad performance. But when I mash <C-c>, it no longer tells me that any plugin code was interrupted.

[ Bug ] Missing entry in aerial treesitter kind_map: impl_item

Describe the bug
A clear and concise description of what the bug is.

System information

  • OS: Linux
  • Neovim version: 0.7.0-dev+876j
  • AerialInfo:
  • Aerial Info

Filetype: rust
Configured backends:
lsp (supported) (attached)
treesitter (supported)
markdown (not supported)
Show symbols: all symbols

  • Aerial config:
vim.g.aerial = {
  -- Enum: persist, close, auto, global
  --   persist - aerial window will stay open until closed
  --   close   - aerial window will close when original file is no longer visible
  --   auto    - aerial window will stay open as long as there is a visible
  --             buffer to attach to
  --   global  - same as 'persist', and will always show symbols for the current buffer
  close_behavior = "global",

  -- Set to false to remove the default keybindings for the aerial buffer
  default_bindings = true,

  -- Enum: prefer_right, prefer_left, right, left
  -- Determines the default direction to open the aerial window. The 'prefer'
  -- options will open the window in the other direction *if* there is a
  -- different buffer in the way of the preferred direction
  default_direction = "left",

  -- Set to true to only open aerial at the far right/left of the editor
  -- Default behavior opens aerial relative to current window
  placement_editor_edge = true,

  -- Fetch document symbols when LSP diagnostics change.
  -- If you set this to false, you will need to manually fetch symbols
  diagnostics_trigger_update = true,

  -- Enum: split_width, full_width, last, none
  -- Determines line highlighting mode when multiple buffers are visible
  highlight_mode = "split_width",

  -- When jumping to a symbol, highlight the line for this many ms
  -- Set to 0 or false to disable
  highlight_on_jump = 300,

  -- Fold code when folding the tree. Only works when manage_folds is enabled
  link_tree_to_folds = true,

  -- Fold the tree when folding code. Only works when manage_folds is enabled
  link_folds_to_tree = false,

  -- Use symbol tree for folding. Set to true or false to enable/disable
  -- 'auto' will manage folds if your previous foldmethod was 'manual'
  manage_folds = "auto",

  -- The maximum width of the aerial window
  max_width = 30,

  -- The minimum width of the aerial window.
  -- To disable dynamic resizing, set this to be equal to max_width
  min_width = 10,

  -- Set default symbol icons to use Nerd Font icons (see https://www.nerdfonts.com/)
  nerd_font = "auto",

  -- Whether to open aerial automatically when entering a buffer.
  -- Can also be specified per-filetype as a map (see below)
  open_automatic = true,

  -- If open_automatic is true, only open aerial if the source buffer is at
  -- least this long
  -- open_automatic_min_lines = 50,

  -- If open_automatic is true, only open aerial if there are at least this many symbols
  open_automatic_min_symbols = 1,

  -- Run this command after jumping to a symbol (false will disable)
  post_jump_cmd = "normal! zz",

  -- Set to false to not update the symbols when there are LSP errors
  update_when_errors = true,

  -- A list of all symbols to display. Set to false to display all symbols.
  filter_kind = false,
}

To Reproduce
Steps to reproduce the behavior:

  1. Open Rust file
  2. Wait for LSP rust-analyzer to attach
  3. Sometimes the error will appear, however, not always.When renaming an item using LSP the error will always appear and prevent rename.

Screenshots
Screenshot from 2022-01-16 12-06-21

Additional context
The error message:

The cause for the error is that the language_kind_map for Rust is incomplete

File: ./lua/aerial/backends/treesitter/language_kind_map.lua,

is missing impl_item in the kind map.

Configuration LSP not working?

I have configured aerial like #34 , but it seems that LSP always can't work correctly.

My config is like this:

-- lsp config {{{
local servers = {
    "gopls",
    "tsserver",
    "html",
    "cssls",
    "tailwindcss",
    "solargraph",
}

function on_attach(client, bufnr)
    local function buf_set_keymap(...)
      vim.api.nvim_buf_set_keymap(bufnr, ...)
    end
    local function buf_set_option(...)
      vim.api.nvim_buf_set_option(bufnr, ...)
    end

    buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc")

    require "lsp_signature".on_attach()
    require("aerial").on_attach(client, bufnr)
end

-- lspInstall + lspconfig stuff

local lsp_installer = require("nvim-lsp-installer")

for _, name in pairs(servers) do
  local ok, server = lsp_installer.get_server(name)
  -- Check that the server is supported in nvim-lsp-installer
  if ok then
    if not server:is_installed() then
      print("Installing " .. name)
      server:install()
    end
  end
end

local nvim_lsp = require('lspconfig')
for _, lsp in ipairs(servers) do
  lsp_installer.on_server_ready(function(lsp)
    local opts = {}
    lsp:setup(opts)
  end)

  nvim_lsp[lsp].setup {
    on_attach = on_attach,
    flags = {
      debounce_text_changes = 150,
    }
  }
end

Then I open a go file, run :AerialInfo command, always get this result:

Aerial Info
-----------
Filetype: go
Configured backends:
  lsp (not supported) [LSP client not attached (did you call aerial.on_attach?)]
  treesitter (supported) (attached)
  markdown (not supported) [Filetype is not markdown]
Show symbols: Class, Constructor, Enum, Function, Interface, Module, Method, Struct

And the aerial toggle window can open, but the fold feature not working.

Is there any wrong in my configurations?

? key for showing help or all aerial keymappings

There are keybindings like o to fold or zM to fold all tree. But remembering or go to the docs for each time the user forget is not so inconvenient.

Please consider adding the feature "press ? key to show all the keybindings or help."

Also, many thanks for making this plugin.

[Statusline Component] symbols persist when the cursor does not have a symbol(blank line)

Describe the bug
Basically for example, in lua when I create a function and I move the cursor inside to the function, the statusline component updates and show the function name, but if I move the cursor outside to the function, the statusline isn't updated.

System information

  • OS: Windows
  • Neovim version: NVIM v0.7.0-dev+922-g1b6ae2dbb
  • AerialInfo:
Aerial Info
-----------
Filetype: lua
Configured backends:
  lsp (supported) (attached)
  treesitter (supported)
Show symbols: Class, Constructor, Enum, Function, Interface, Module, Method, Struct
  • Aerial config:
require("aerial").setup({
    backends = { "lsp", "treesitter" },
    open_automatic = true,
    max_width = 30,
    min_width = 30,
})

To Reproduce
Steps to reproduce the behavior:

  1. Just use the lualine component

If possible, provide a minimal file that will trigger the issue:

--------------------------

local function test()
    -- content
end

--------------------------

Screenshots
https://gyazo.com/3f8e39591f46af5a331e964a99015417
when the cursor is in a blank line(or comment), statusline component shouldn't show <Anonymous>

Usage of deprecated API vim.lsp.diagnostic

Describe the bug
As of neovim 0.7+ the vim.lsp.diagnostic API is deprecated. Aerial still makes use of this api and leads to warnings and failure to load the window.

System information

  • OS: Linux
  • Neovim version: 0,.7 + 666
  • AerialInfo: [output of :AerialInfo]

To Reproduce
Steps to reproduce the behavior:

  1. Open a file
  2. Open aerial buffer

Error 'handle is already closing' when using AerialToggle

When I open earial from code which is folded:
image

I get error bisible at bottom
If I unfold code (zR - unfolds all ) - then aeria windowl opens no problem.

My config:
Treesitter for folding:

vim.wo.foldmethod="expr"
vim.wo.foldexpr="nvim_treesitter#foldexpr()"  
vim.wo.foldenable=true    

and aerial config:

vim.g.aerial = {
  close_behavior = 'close',
  default_bindings = true,
  default_direction = 'prefer_right',
  diagnostics_trigger_update = true,
  highlight_mode = 'split_width',
  highlight_on_jump = 300,
  link_tree_to_folds = false,
  link_folds_to_tree = false,
  manage_folds = false,

  nerd_font = 'auto',

  open_automatic = false,

  post_jump_cmd = 'normal! zzzo',

  filter_kind = {
    "Class",
    "Constructor",
    "Enum",
    "Function",
    "Interface",
    "Method",
    "Struct",
  },
}     

Aerial gets stuck on items generated by macros.

I'm trying out aerial on the llvm codebase with clangd as the LSP. It's pretty neat.

The }} binding works, but appears to get stuck on items that are generated by macros.

For example here:
image

Pressing }} does not advance to the next item in the tree.

The macro from this example is defined as:

  #define INITIALIZE_PASS(passName, arg, name, cfg, analysis)                    \                                                                        
    static void *initialize##passName##PassOnce(PassRegistry &Registry) {        \                                                                        
      PassInfo *PI = new PassInfo(                                               \                                                                        
          name, arg, &passName::ID,                                              \                                                                        
          PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis);     \                                                                        
      Registry.registerPass(*PI, true);                                          \                                                                        
      return PI;                                                                 \                                                                        
    }                                                                            \                                                                        
    static llvm::once_flag Initialize##passName##PassFlag;                       \                                                                        
    void llvm::initialize##passName##Pass(PassRegistry &Registry) {              \                                                                        
      llvm::call_once(Initialize##passName##PassFlag,                            \                                                                        
                      initialize##passName##PassOnce, std::ref(Registry));       \                                                                        
    }                                                                                 

Expose current symbol via API

It would be nice to expose current symbol via API, so it can be used and shown in status line. Since aerial.nvim already deals with symbols, it seems just reasonable to expose this information so it can be used by third party plugins. It'd be nice to return some sort of AST, e.g.:

{
   { lsp_kind = "Class",  name = "MyClass" },  -- maybe the default `icon` should be returned too :thinking: 
   { lsp_kind = "Method", name = "foobar" },
   { lsp_kind = "Variable", name = "myvar" },
}
  • The nodes returned are only those that weren't filtered out by aerial.nvim (i.e. filter_kind is respected)
  • How to format the end line is up to user. Some may want to show only the method name, others -- the full path.

There are plugins out there that provide similar functionality and have their own drawbacks.

  • liuchengxu/vista.vim
    • Does not support treesitter. It's either LSP or ctags or custom providers.
    • Returns only function or method.
    • Does not expose information about parent nodes.
  • SmiteshP/nvim-gps
    • Does not provide enough flexibility on how to render the line.
    • Does nothing useful except for the status line formatting.

Aerial doesn't play well with wfxr/minimap.vim

Describe the bug
When using wfxr/minimap.vim the position/default-direction of the aerial pane is wrong.
In case I put position right: It puts itself to the right of the minimap (which is on the right side already ... and doesn't find symbols and doesn't work - maybe because it is looking into the minimap as source? - and when being closed the minimap pane is resized improperly)
in case i put position left: it puts itself to the right of the buffer (in between buffer and minimap) and works just fine (which is the setup I'm using now, though I wanted to try and put it left and see how I go with that ...)

System information

  • OS: MacOs Monterey
  • Neovim version: 0.6.1
  • AerialInfo:
    Filetype: lua
    Configured backends:
    lsp (supported) (attached)
    treesitter (supported)
    markdown (not supported) [Filetype is not markdown]
    Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct

To Reproduce
Steps to reproduce the behavior:

  1. install wfxr/minimap.vim alongside
  2. open the minimap first, then open the aerial pane in any supported filetype buffer
  3. see how the aerial window positions itself too far right or unexpectedly to the right instead of to the left, and in case of far right doesn't work/find symbols

If possible, provide a minimal file that will trigger the issue:
sorry, got none ...

Screenshots
8F3B3FD4-F7BB-4908-974C-680B7A106004

Additional context
Actually, when I put position left and it works, but positions itself to the right, it only sometimes works.
Sometimes it doesn't find symbols, sometimes it does (don't know exactly).
What might be useful though - is, that if it works (shows symbols) it will first throw this Error and then on user confirmation of the Nvim error it continues to show the symbols:
Error executing vim.schedule lua callback: ...site/pack/packer/start/aerial.nvim/lua/aerial/render.lua:137: attempt to index a nil value
stack traceback:
...site/pack/packer/start/aerial.nvim/lua/aerial/render.lua:137: in function 'update_highlights'
...site/pack/packer/start/aerial.nvim/lua/aerial/render.lua:97: in function 'update_aerial_buffer'
...ck/packer/start/aerial.nvim/lua/aerial/backends/init.lua:91: in function 'set_symbols'
.../start/aerial.nvim/lua/aerial/backends/lsp/callbacks.lua:71: in function 'handle_symbols'
.../start/aerial.nvim/lua/aerial/backends/lsp/callbacks.lua:109: in function 'fn'
vim.lua:415: in function 'cb'
vim.lua:285: in function vim.lua:285

Aerial not updating

Describe the bug
Aerial is not updating(with sumneko_lua, pyright does works) the window

System information

  • OS: Windows
  • Neovim version: NVIM v0.7.0-dev+991-g547497b04
  • AerialInfo:
Aerial Info
-----------
Filetype: lua
Configured backends:
  lsp (supported) (attached)
Show symbols: Class, Constructor, Enum, Function, Interface, Module, Method, Struct
  • Aerial config:
require("aerial").setup({
    backends = { "lsp" },--"treesitter" },
    default_direction = "right",
    open_automatic = true,
    max_width = 30,
    min_width = 30,
})

To Reproduce
Steps to reproduce the behavior:

  1. Wait for sumneko lua loaded.
  2. :AerialOpen
  3. write a new local function

Screenshots
https://gyazo.com/a50d37cea472bd3d78c174ba18b25607

Aditional Context
maybe it's a sumneko_lua problem, but I'm not sure

[Feature Request] Equal window size after open

When the aerial window opens, it will 'steal' size from the parent window from which it was opened from. If you have many vertical splits open the split with an Aerial window open will be slightly thinner.

I suggest an option that will automatically execute wincmd = on window opening, which will balance the size of all windows except fixwidth windows like aerial.

Another option would be to respect the value of equalalways

Feature request, add PHP as treesitter language

Language: PHP

Below a minimal PHP file that includes the main language constructs. I'm not a PHP dev but I need to read PHP code regularly, so I took example code from https://learnxinyminutes.com/docs/php/

function my_function () {
    return 'Hello';
}

function add ($x, $y = 1) {
    $result = $x + $y;
    return $result;
}

$inc = function ($x) {
    return $x + 1;
};
function bar ($x, $y) {
    return function ($z) use ($x, $y) {
        foo($x, $y, $z);
    };
}

class MyClass
{
    const MY_CONST      = 'value'; 

    static $staticVar   = 'static';

    public static $publicStaticVar = 'publicStatic';
    private static $privateStaticVar = 'privateStatic';
    protected static $protectedStaticVar = 'protectedStatic';

    public $property    = 'public';
    public $instanceProp;
    protected $prot = 'protected';
    private $priv   = 'private';

    public function __construct($instanceProp)
    {
        $this->instanceProp = $instanceProp;
    }

    public function myMethod()
    {
        print 'MyClass';
    }

    final function youCannotOverrideMe()
    {
    }

    public function __toString()
    {
        return $property;
    }

    public function __destruct()
    {
        print "Destroying";
    }

    public static function myStaticMethod()
    {
        print 'I am static';
    }
}

class MyOtherClass extends MyClass
{
    function printProtectedProperty()
    {
        echo $this->prot;
    }

    function myMethod()
    {
        parent::myMethod();
        print ' > MyOtherClass';
    }
}

final class YouCannotExtendMe
{
}

interface InterfaceOne
{
    public function doSomething();
}

interface InterfaceTwo
{
    public function doSomethingElse();
}

interface InterfaceThree extends InterfaceTwo
{
    public function doAnotherContract();
}

abstract class MyAbstractClass implements InterfaceOne
{
    public $x = 'doSomething';
}

class MyConcreteClass extends MyAbstractClass implements InterfaceTwo
{
    public function doSomething()
    {
        echo $x;
    }

    public function doSomethingElse()
    {
        echo 'doSomethingElse';
    }
}

class SomeOtherClass implements InterfaceOne, InterfaceTwo
{
    public function doSomething()
    {
        echo 'doSomething';
    }

    public function doSomethingElse()
    {
        echo 'doSomethingElse';
    }
}
trait MyTrait
{
    public function myTraitMethod()
    {
        print 'I have MyTrait';
    }
}

class MyTraitfulClass
{
    use MyTrait;
}

I've seen there is treesitter query for function and class in the nvim-gps plugin https://github.com/SmiteshP/nvim-gps/blob/master/queries/php/nvimGPS.scm

I wonder if some work could be shareable between the two project ?

Thank you for your plugin !

How to set up with nvim-lsp-installer?

I've been trying to get this to hook into the on_attach that gets passed to the server:setup(opts) call in lsp_installer.on_server_ready(function(server) ... end) without much success. Am I supposed to be doing it differently? Do you have instructions for how to configure this with nvim-lsp-installer?

add Julia language

Language: Julia

module M

const X = nothing  # global const

function f()  # function
end

g() = nothing  # single line function

abstract type A end

struct B <: A
    B() = new()  # inner constructor
end

end

Hi, it seems that the tree-sitter back-end is working reliably now, and I'm interested in using this package. Personally, I'm only interested in the tree-sitter back-end, but there are some Julia users who use LSP in nvim, so there may be interest in that as well.

Error when file contains too many symbols

Describe the bug
See screenshot below:

image

System information

  • OS: Linux
  • Neovim version: NVIM v0.7.0-dev+863-g8f27c4a04
  • AerialInfo:
Aerial Info                                                                                                                                                                      
-----------
Filetype: lua
Configured backends:
  lsp (supported) (attached)
  treesitter (supported)
  markdown (not supported) [Filetype is not markdown]
Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct

This is a bit mis-leading as the error is happening in a work environment where I cannot copy/paste from easily.

To Reproduce
Steps to reproduce the behavior:

  1. Run :AerialToggle in a file with a large number of symbols

Not a minimal configuration, however this is what I use:

  require("aerial").setup({
    close_behavior = "close",
    default_bindings = true,
    default_direction = "float",
    diagnostics_trigger_update = true,
    highlight_mode = "split_width",
    highlight_on_jump = 300,
    link_tree_to_folds = true,
    link_folds_to_tree = false,
    manage_folds = "auto",
    max_width = 40,
    min_width = 10,
    nerd_font = "auto",
    open_automatic = false,
    post_jump_cmd = "normal! zz",
    close_on_select = true,
    update_when_errors = true,
    float = {
      max_height = 500,
      min_height = 4,
    },
    filter_kind = {
      "Class",
      "Constructor",
      "Enum",
      "Function",
      "Interface",
      "Method",
      "Struct",
    },
    icons = {
      Class = "",
      ClassCollapsed = "",
      Function = "",
      Constant = "",
      Collapsed = "▶",
    },
  })

Screenshots
See above.

Additional context
I will add some debug logs and attempt to figure out what the arguments that it is passing to open the floating window are, versus the actual size of the window itself.

Javascript Jest support

Language: Javascript

Example file:

import FormCreate from '@/components/FormCreate'
import { nextTick } from '@vue/runtime-core'
import { factory } from '../helpers'

describe('FormCreate', () => {
    describe('save', () => {
        const wrapper = factory({ component: FormCreate })

        it('Return when name is empty', async () => {
            wrapper.vm.input.name = ''
            expect(await wrapper.vm.save()).toBe(false)
        })

        it('Dispatch "createNewConnector"', async () => {
            wrapper.vm.input.name = 'component_name'
            await wrapper.vm.save()
            // this test is only to make sure no error happened
            // further test should be runs for store.js
        })
    })

    describe('cancel', () => {
        const wrapper = factory({ component: FormCreate })

        it('Emit "cancel" when cancel', () => {
            wrapper.vm.cancel()
            expect(wrapper.emitted().cancel[0]).toEqual([])
        })

        it('Reset when cancel', () => {
            wrapper.vm.cancel()
            expect(wrapper.vm.input.name).toBe('')
            expect(wrapper.vm.input.description).toBe('')
            expect(wrapper.vm.showNotification).toBe(false)
            expect(wrapper.vm.saved).toBe(false)
        })
    })

    describe('focusInput', () => {
        const wrapper = factory({ component: FormCreate })
        it('focusing input', async () => {
            wrapper.vm.focusInput()
            expect(wrapper.get('input').element).toEqual(document.activeElement)
        })
    })
})

Similar to my request for Ruby Rspec files, if I run aerial on this I receive No symbols.

quick jump

can u add quick jump feature, such as fzf integration like vscode , look's like more useful for keyboard

Aerial window changes position when quickfix window is open

Describe the bug
When quickfix window is opened first, aerial opened second, the side where aerial opens changes. Otherwise desired behavior is shown ( when aerial opened first without quickfix or aerial first quickfix second )

System information

  • OS: Arch Linux
  • Neovim version:
NVIM v0.6.1
Build type: Release
LuaJIT 2.0.5
Compiled by builduser

Features: +acl +iconv +tui
See ":help feature-compile"

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/usr/share/nvim"

Run :checkhealth for more info
  • AerialInfo: [output of :AerialInfo]
  • Aerial config:
local aerial = require'aerial'

aerial_on_attach = function(bufnr)
    -- Toggle the aerial window with <leader>aa
    vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>aa', '<cmd>AerialToggle!<CR>', {})
  end

-- Call the setup function to change the default behavior
require("aerial").setup({
  -- Priority list of preferred backends for aerial.
  -- This can be a filetype map (see :help aerial-filetype-map)
  backends = { "lsp", "treesitter", "markdown" },

  -- Enum: persist, close, auto, global
  --   persist - aerial window will stay open until closed
  --   close   - aerial window will close when original file is no longer visible
  --   auto    - aerial window will stay open as long as there is a visible
  --             buffer to attach to
  --   global  - same as 'persist', and will always show symbols for the current buffer
  close_behavior = "close",

  -- Set to false to remove the default keybindings for the aerial buffer
  default_bindings = true,

  -- Enum: prefer_right, prefer_left, right, left, float
  -- Determines the default direction to open the aerial window. The 'prefer'
  -- options will open the window in the other direction *if* there is a
  -- different buffer in the way of the preferred direction
  default_direction = "prefer_right",

  -- Disable aerial on files with this many lines
  disable_max_lines = 10000,

  -- A list of all symbols to display. Set to false to display all symbols.
  -- This can be a filetype map (see :help aerial-filetype-map)
  -- To see all available values, see :help SymbolKind
  filter_kind = {
    "Class",
    "Constructor",
    "Enum",
    "Function",
    "Interface",
    "Method",
    "Struct",
  },

  -- Enum: split_width, full_width, last, none
  -- Determines line highlighting mode when multiple splits are visible
  -- split_width   Each open window will have its cursor location marked in the
  --               aerial buffer. Each line will only be partially highlighted
  --               to indicate which window is at that location.
  -- full_width    Each open window will have its cursor location marked as a
  --               full-width highlight in the aerial buffer.
  -- last          Only the most-recently focused window will have its location
  --               marked in the aerial buffer.
  -- none          Do not show the cursor locations in the aerial window.
  highlight_mode = "split_width",

  -- When jumping to a symbol, highlight the line for this many ms.
  -- Set to false to disable
  highlight_on_jump = 300,

  -- Define symbol icons. You can also specify "<Symbol>Collapsed" to change the
  -- icon when the tree is collapsed at that symbol, or "Collapsed" to specify a
  -- default collapsed icon. The default icon set is determined by the
  -- "nerd_font" option below.
  -- If you have lspkind-nvim installed, aerial will use it for icons.
  icons = {},

  -- When you fold code with za, zo, or zc, update the aerial tree as well.
  -- Only works when manage_folds = true
  link_folds_to_tree = false,

  -- Fold code when you open/collapse symbols in the tree.
  -- Only works when manage_folds = true
  link_tree_to_folds = true,

  -- Use symbol tree for folding. Set to true or false to enable/disable
  -- 'auto' will manage folds if your previous foldmethod was 'manual'
  manage_folds = false,

  -- The maximum width of the aerial window
  max_width = 40,

  -- The minimum width of the aerial window.
  -- To disable dynamic resizing, set this to be equal to max_width
  min_width = 10,

  -- Set default symbol icons to use patched font icons (see https://www.nerdfonts.com/)
  -- "auto" will set it to true if nvim-web-devicons or lspkind-nvim is installed.
  nerd_font = "auto",

  -- Call this function when aerial attaches to a buffer.
  -- Useful for setting keymaps. Takes a single `bufnr` argument.
  -- on_attach = nil,
  on_attach = aerial_on_attach,

  -- Automatically open aerial when entering supported buffers.
  -- This can be a function (see :help aerial-open-automatic)
  open_automatic = false,

  -- Set to true to only open aerial at the far right/left of the editor
  -- Default behavior opens aerial relative to current window
  placement_editor_edge = false,

  -- Run this command after jumping to a symbol (false will disable)
  post_jump_cmd = "normal! zz",

  -- When true, aerial will automatically close after jumping to a symbol
  close_on_select = false,

  -- Options for opening aerial in a floating win
  float = {
    -- Controls border appearance. Passed to nvim_open_win
    border = "rounded",

    -- Controls row offset from cursor. Passed to nvim_open_win
    row = 1,

    -- Controls col offset from cursor. Passed to nvim_open_win
    col = 0,

    -- The maximum height of the floating aerial window
    max_height = 100,

    -- The minimum height of the floating aerial window
    -- To disable dynamic resizing, set this to be equal to max_height
    min_height = 4,
  },

  lsp = {
    -- Fetch document symbols when LSP diagnostics change.
    -- If you set this to false, you will need to manually fetch symbols
    diagnostics_trigger_update = true,

    -- Set to false to not update the symbols when there are LSP errors
    update_when_errors = true,
  },

  treesitter = {
    -- How long to wait (in ms) after a buffer change before updating
    update_delay = 300,
  },

  markdown = {
    -- How long to wait (in ms) after a buffer change before updating
    update_delay = 300,
  },
})

To Reproduce
Steps to reproduce the behavior:

  1. Open quickfix window copen
  2. Open aerial window AerialToggle
  3. Close aerial window AerialToggle
  4. Close quickfix window cclose
  5. Open aerial window AerialToggle

If possible, provide a minimal file that will trigger the issue:
Showing in all files

Screenshots
aerial1
aerial2

Additional context
Not a big problem, can be ignored.

[Lua] Files with local and global scoped functions not displaying as expected

Describe the bug
I've noticed that when I have a lua file which has a mixture of local and global functions, Aerial only displays the local ones. Yet when I have a file of just global functions, it displays them as expected.

System information

  • OS: mac
  • Neovim version: 0.6.1
  • AerialInfo:
Filetype: lua
Configured backends:
  lsp (not supported) [LSP client not attached (did you call aerial.on_attach?)]
  treesitter (supported) (attached)
  markdown (not supported) [Filetype is not markdown]
Show symbols: Class, Constructor, Enum, Function, Interface, Module, Method, Struct
  • Aerial config:
aerial.setup({
  close_on_select = true,
  default_direction = "prefer_right",
  min_width = 40
})

To Reproduce
Steps to reproduce the behavior:

  1. Load functions.lua in Neovim, open Aerial and observe all functions working as expected
  2. Load utils.lua in Neovim, open Aerial and observe that only local functions are displayed

Screenshots

functions.lua
Screen Shot 2022-01-26 at 09 14 05@2x

utils.lua
Screen Shot 2022-01-26 at 09 13 02@2x

Allow rearranging code from the symbols window

I think this should be straightforward, if not easy, for the markdown and treesitter backends. LSP might be more difficult. Also since we're usually filtering out some symbol types, it could maybe produce unexpected results for the user. Will need to test out a MVP to see if this could work or if it has too many issues.

Configuration help

I am having trouble with setting up aerial.

If I have default lspconfig like this

local on_attach = function(client, bufnr)
  local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
  local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

  -- Enable completion triggered by <c-x><c-o>
  buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

  -- Mappings.
  local opts = { noremap=true, silent=true }

  -- See `:help vim.lsp.*` for documentation on any of the below functions
  buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
  buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
  buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
  -- other keybindings ...

end

do I configure aerial like this ?

local on_attach = function(client, bufnr)
  local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
  local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

  -- Enable completion triggered by <c-x><c-o>
  buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

  -- Mappings.
  local opts = { noremap=true, silent=true }

  -- See `:help vim.lsp.*` for documentation on any of the below functions
  buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
  buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
  buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
  -- other keybindings ...

  require'aerial'.on_attach()

end

I am not able to get both working together.

Aerial forces pane height on opening

Hi this issue happens when I have 2 panes open with a horizontal split. If one pane is taller than the other and I open aerial, it forces both panes to assume the same height.

I hope this explains itself and if not happy to provide a gif of the issue

Thanks a lot for the great plugin btw!

Ignore URI's that are not `file://`

Describe the bug
Aerial should not be opened in git diff or other URI's that are not file:// (or make it optional)

Aerial config

require("aerial").setup({
    default_direction = "right",
    highlight_closest = false,
    open_automatic = true,
    max_width = 30,
    min_width = 30,
    treesitter = {
        update_delay = 150,
    },
    markdown = {
        update_delay = 150,
    },
    lsp = {
        update_delay = 150,
        diagnostics_trigger_update = false,
    },
})

Screenshots
https://gyazo.com/55b706b9ce7402e4b75384972a21fada

`:Telescope aerial` showing way less results than `:Telescope lsp_document_symbols` picker

Describe the bug

Hello! In the README, it says:

If you have telescope installed, there is an extension for fuzzy finding and jumping to symbols. It functions similarly to the builtin lsp_document_symbols picker.

For me, it seems like Aerial is showing way less results than lsp_document_symbols. Here's the Telescope builtin results for a sample file I have (excuse the whacky colors):

image

And then this is what I see with :Telescope aerial on the same file (fwiw, this is also what's shown in the Aerial window, so I don't think this is a Telescope problem)

image

Am I doing something wrong? My basic configuration looks like this (I install LSP backends with nvim-lsp-installer, and things seem to be configured okay for most things):

local lsp_installer = require("nvim-lsp-installer")
lsp_installer.on_server_ready(function(server)
    local opts = {}
    local aerial = require("aerial")

    opts.on_attach = function(client)
        -- other configs

        aerial.on_attach(client)
    end

    server:setup(opts)
end)

System information

  • OS: macOS 12.0.1
  • Neovim version: 0.6.0
  • AerialInfo:
Aerial Info
-----------
Filetype: lua
Configured backends:
  lsp (supported) (attached)
  treesitter (supported)
  markdown (not supported)
Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct

To Reproduce
Steps to reproduce the behavior:

  1. Compare the output of :Telescope aerial and :Telescope lsp_document_symbols

[Low Priority] Add Ruby RSpec file to aerial.nvim

Language: Ruby

As per discussions on #35, adding function calls for a Ruby RSpec file.

Example language file (taken from here)

require 'spec_helper'
require 'json'
require 'date'

# Unit tests for SquareConnect::V1ModifierOption
# Automatically generated by swagger-codegen (github.com/swagger-api/swagger-codegen)
# Please update as you see appropriate
describe 'V1ModifierOption' do
  before do
    # run before each test
    @instance = SquareConnect::V1ModifierOption.new
  end

  after do
    # run after each test
  end

  describe 'test an instance of V1ModifierOption' do
    it 'should create an instact of V1ModifierOption' do
      expect(@instance).to be_instance_of(SquareConnect::V1ModifierOption)
    end
  end
  describe 'test attribute "id"' do
    it 'should work' do
       # assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
    end
  end

  describe 'test attribute "name"' do
    it 'should work' do
       # assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
    end
  end

  describe 'test attribute "price_money"' do
    it 'should work' do
       # assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
    end
  end

  describe 'test attribute "on_by_default"' do
    it 'should work' do
       # assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
    end
  end

  describe 'test attribute "ordinal"' do
    it 'should work' do
       # assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
    end
  end

  describe 'test attribute "modifier_list_id"' do
    it 'should work' do
       # assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
    end
  end

end

Thoughts on implementation

Appreciate that implementing function calls could lead to aerial.nvim becoming bloated from a UI perspective. Is there anyway to load function calls for specific file types or names like _spec.rb?

the function return pointer in cpp

Language: cpp
AerialInfo:

Filetype: cpp
Configured backends:
lsp (not supported)
treesitter (supported) (attached)
markdown (not supported)
Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct

The minimal amount of code that demonstrates the missing symbol:

int* bar() {}

Expected symbol: bar

Provide "AerialDisable" and "AerialEnable" commands to disable/enable aerial (useful when current window is vertically split)

Describe the bug
I like aerial's open_automatic option to be set to true. This helps with discoverability (otherwise I can't remember what features I have in my editor due to many useful plugins and interesting plugins installed).

However, when viewing vertical diffs, this quickly becomes a problem. Even with the below two options,

 placement_editor_edge = true,
 close_behavior = "global",`
``
and after explicitly closeing the aerial window with the `:AerialClose` command, the global aerial window annoyingly reopens when jumping between visible buffers (windows). This takes up valuable real estate, especially when working on a small-screen 14" laptop.

**System information**
- OS: Linux
- Neovim version: 0.6.0
- AerialInfo: 

Aerial Info

Filetype: lua                                                                                                                            
Configured backends:                                                                                                                     
  lsp (not supported)                                                                                                                    
  treesitter (supported) (attached)                                                                                                      
  markdown (not supported)                                                                                                               
Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct 

Screenshot
image

Desired Solution
Please provide a command such as :AerialDisable that will permanently close aerial for the current vim session (or at least until a companion command :AerialEnable is run).

New markdown file causes error on nil value.

Describe the bug
Aerial drops this error when a new markdown file has no symbols yet.

Error executing vim.schedule lua callback: ...erial.nvim/lua/aerial/backends/treesitter/extensi
ons.lua:49: attempt to index local 'prev' (a nil value)
stack traceback:
...erial.nvim/lua/aerial/backends/treesitter/extensions.lua:49: in function 'set_end_ra
nge'
...erial.nvim/lua/aerial/backends/treesitter/extensions.lua:74: in function 'postproces
s_symbols'
.../packer/opt/aerial.nvim/lua/aerial/backends/markdown.lua:51: in function 'fetch_symb
ols'
...pack/packer/opt/aerial.nvim/lua/aerial/backends/util.lua:41: in function 'cb'
vim.lua:291: in function vim.lua:291

System information

  • OS: [mac]
  • Neovim version:
  • AerialInfo: [output of :AerialInfo]
  • Aerial config:
-- Paste your call to require("aerial").setup(...) in here
      "stevearc/aerial.nvim",                                    
      event = "BufReadPost",                                     
      config = function()                                        
         require("aerial").setup {                               
            backends = {                                         
               -- use underscore to specify the default behavior 
               ["_"] = { "lsp", "treesitter", "markdown" },      
               ["vimwiki.markdown.pandoc"] = { "treesitter" },   
               python = { "treesitter" },                        
               rust = { "lsp" },                                 
            },                                                   
            show_guides = true,                                  
            default_direction = "prefer_left",                   
            open_automatic = false,                                                      
         }                                                       
      end,                                                       

After upgrading to latest treesitter aerial throwing an exception

Treesitter replaced lua parser with a new one in this PR
After upgrading treesitter, aerial is failing when opening lua files:

Error executing vim.schedule lua callback: /usr/share/nvim/runtime/lua/vim/treesitter/query.lua:172: query: invalid node type at position 1
stack traceback:
        [C]: in function '_ts_parse_query'
        /usr/share/nvim/runtime/lua/vim/treesitter/query.lua:172: in function 'get_query'
        ...cker/start/nvim-treesitter/lua/nvim-treesitter/query.lua:91: in function 'get_query'
        ...cker/start/nvim-treesitter/lua/nvim-treesitter/query.lua:302: in function 'iter_group_results'
        ...tart/aerial.nvim/lua/aerial/backends/treesitter/init.lua:48: in function 'fetch_symbols'
        ...tart/aerial.nvim/lua/aerial/backends/treesitter/init.lua:105: in function 'attach'
        ...ck/packer/start/aerial.nvim/lua/aerial/backends/init.lua:49: in function 'attach'
        ...ck/packer/start/aerial.nvim/lua/aerial/backends/init.lua:68: in function 'get'
        ...ck/packer/start/aerial.nvim/lua/aerial/backends/init.lua:121: in function 'attach'
        ...ack/packer/start/aerial.nvim/lua/aerial/autocommands.lua:28: in function ''
        vim.lua: in function <vim.lua:0>

System information

  • OS: linux
  • Neovim version: NVIM v0.7.0-dev+906-gde6f9233e
  • AerialInfo:
Filetype:
Configured backends:
  lsp (not supported) [LSP client not attached]
  treesitter (not supported) [No treesitter parser for ]
  markdown (not supported) [Filetype is not markdown]
Show symbols: Class, Constructor, Enum, Function, Interface, Module, Method, Struct
  • Aerial config:
    Nothing specific, just default config.

To Reproduce
Steps to reproduce the behavior:

  1. Upgrade to latest treesitter
  2. Open any lua file
  3. See the error message

Doesn't work with multi-filetypes.

I have a really niche use case here. Both Vim and Neovim have a handy feature that allows a file to be recognized as multiple filetypes, then various scripts and autogroup actions can be ran for each of the filetypes that applies. As an example I'm using the Vimwiki plugin to edit markdown files, some types of markdown can also be considered a pandoc file as well. In neovim if I open a markdown file and issue the command :set filetype it shows the current filetype as vimwiki.markdown.pandoc as expected. However, this plugin doesn't recognize this as a list of filetypes. Instead, as far as I can tell, it recognizes a single filetype vimwiki.markdown.pandoc and doesn't open. For reference both Tagbar and Vista.vim work out of the box in recognizing the markdown structure in this case. At any rate, thanks again for this rad plugin!

System information

  • OS: mac
  • Neovim version: v0.7.0-dev+758-g0c35fd5fc

Aerial Info

Filetype: vimwiki.markdown.pandoc
Configured backends:
lsp (not supported)
treesitter (not supported)
markdown (not supported)
Show symbols: Class, Constructor, Enum, Function, Interface, Method, Struct

Infinite loading

Not entirely sure how to go about debugging this one, however I'd imagine that I should first try having a more minimal configuration to see if something else is conflicting, etc.

Whenever I AerialToggle, I am just faced with the quickfix list being opened, and then what is seemingly the Aerial buffer just infinitely loading. I've tried this with Python, Lua, and C language servers (all of which work just fine) and get the same thing for all three. Something like this (note that I intentionally have syntax errors to show that the language server is indeed working):

image

I've gone through the LSP logs (although I wouldn't expect them to show anything), etc. and haven't found anything of interest.

How do you suggest I go about debugging this? What else can I dump here?

Aerial with tsitter - constantly opens qfix list - after any character press

Describe the bug
After disabling require'aerial'.on_attach(client) - outliner in lsp, and restarting aerial it should use telescope - and it works. Except after switching buffer, aerial will now constantly open qfix list when going into insert mode and typing any characters like seen below:

AeiralQfixPopup
This makes it impossible to work.
System information

  • OS: [linux]

  • Neovim version:

  • NVIM v0.6.0-dev+594-g36538417f
    Build type: Debug
    LuaJIT 2.1.0-beta3

  • AerialInfo: [output of :AerialInfo]
    image

To Reproduce
Steps to reproduce the behavior:

  1. Disable aerial lsp. And restart nvim
  2. Open any project - editing first buffer works ok. Aerial works ok too
  3. open other file (:e some.file.py) - now aerial will constantly open qfix window. Opening aerial itself gives error:
    image

Additional context
Works ok on lsp.

Feature request: tree-like hierarchy ascii

Consider this truncated output from running tree lib in https://github.com/knpwrs/dotfiles:

❯ tree lib
lib
├── snm.zsh
├── spell
│   ├── en.utf-8.add
│   ├── en.utf-8.add.spl
│   └── sort.sh
├── starship.zsh
├── sublime.zsh
├── terminal.app.zsh
├── terraform.zsh
├── tmux.zsh
├── transfer.zsh
├── yarn.zsh
└── zoxide.zsh

It would be great to have those branch ascii art things in Aerial so it would be easier to see the hierarchy.

Allow opening floating windows not relative to the cursor

Hello!

I've noticed that an option for opening Aerial as a floating window relative to the cursor was added with issue #23. It would be nice, however, to also support opening a floating window that is not relative to the cursor, akin to Fzf/Telescope.

If I'm not mistaken, this would mean an alternate call to nvim_open_win with relative set to "editor", and with width, height, row and col set in a manner to have some padding.

In terms of adding this to the config, I propose the following: add a field to the float section, relative, which can be either "cursor" or "editor" (and maybe also "buffer" in the future?). If it's "cursor" (the default), then it follows the current logic, reading the row, col, max_height and min_height fields. However, if it's set to "editor", then it should look for padding_x and padding_y fields. The shape of the floating window would then be as follows, where w and h are the width and height of the terminal: width = w - 2*floor(padding_x*w), height = h - 2*floor(padding_y*h), row = floor(padding_y*h), col = floor(padding_x*w).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.