Full Code of ldelossa/litee.nvim for AI

main 4efaf373322d cached
30 files
125.1 KB
32.2k tokens
1 requests
Download .txt
Repository: ldelossa/litee.nvim
Branch: main
Commit: 4efaf373322d
Files: 30
Total size: 125.1 KB

Directory structure:
gitextract_v9v813bt/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── README.md
├── doc/
│   ├── litee.txt
│   └── tags
└── lua/
    └── litee/
        └── lib/
            ├── commands.lua
            ├── config.lua
            ├── details/
            │   └── init.lua
            ├── highlights/
            │   ├── auto.lua
            │   └── init.lua
            ├── icons/
            │   └── init.lua
            ├── init.lua
            ├── jumps/
            │   └── init.lua
            ├── lsp/
            │   ├── hover.lua
            │   ├── init.lua
            │   └── wrappers.lua
            ├── navi/
            │   └── init.lua
            ├── notify/
            │   └── init.lua
            ├── panel/
            │   ├── autocmds.lua
            │   └── init.lua
            ├── state/
            │   ├── autocmds.lua
            │   └── init.lua
            ├── term/
            │   └── init.lua
            ├── tree/
            │   ├── init.lua
            │   ├── marshal/
            │   │   └── init.lua
            │   └── node.lua
            └── util/
                ├── buffer.lua
                ├── init.lua
                ├── path.lua
                └── window.lua

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [ldelossa]


================================================
FILE: .gitignore
================================================
notes.md


================================================
FILE: README.md
================================================
```
██╗     ██╗████████╗███████╗███████╗   ███╗   ██╗██╗   ██╗██╗███╗   ███╗
██║     ██║╚══██╔══╝██╔════╝██╔════╝   ████╗  ██║██║   ██║██║████╗ ████║ Lightweight
██║     ██║   ██║   █████╗  █████╗     ██╔██╗ ██║██║   ██║██║██╔████╔██║ Integrated
██║     ██║   ██║   ██╔══╝  ██╔══╝     ██║╚██╗██║╚██╗ ██╔╝██║██║╚██╔╝██║ Text
███████╗██║   ██║   ███████╗███████╗██╗██║ ╚████║ ╚████╔╝ ██║██║ ╚═╝ ██║ Editing
╚══════╝╚═╝   ╚═╝   ╚══════╝╚══════╝╚═╝╚═╝  ╚═══╝  ╚═══╝  ╚═╝╚═╝     ╚═╝ Environment
====================================================================================
```

![litee screenshot](./contrib/litee-screenshot.png)

# litee.nvim

Litee.nvim (pronounced lite) is a library for building "IDE-lite" experiences in Neovim. 

By utilizing the "litee" library plugin authors can achieve a consistent experience
across separate plugins.

There are several official litee plugins which can act as a reference for implementing
additional.

## Calltree
https://github.com/ldelossa/litee-calltree.nvim

Analogous to VSCode's "Call Hierarchy" tool, this plugin exposes an explorable tree
of incoming or outgoing calls for a given symbol. 

Unlike other Neovim plugins, the tree can be expanded and collapsed to discover 
"callers-of-callers" and "callees-of-callees" until you hit a leaf.

## Symboltree
https://github.com/ldelossa/litee-symboltree.nvim

Analogous to VSCode's "Outline" tool, this plugin exposes a live tree of document
symbols for the current file. 

The tree is updated as you move around and change files.

## Filetree
https://github.com/ldelossa/litee-filetree.nvim

Analogous to VSCode's "Explorer", this plugin exposes a full feature file explorer 
which supports recursive copies, recursive moves, and proper renaming of a file 
(more on this in the appropriate section).

## Bookmarks
https://github.com/ldelossa/litee-bookmarks.nvim

This plugin exposes a way to create Bookmarks, pinnable areas of important
code, and organize them into one or more Notebooks.

Notebooks allow you to open and close sets of Bookmarks depending on what
you're working on that day.

# Usage

litee.nvim is a library which other plugins can important and use. 

The library has it's own configuration and setup function which can be
viewed in the `doc.txt`.

An example of configuring the library is below:

```
require('litee.lib').setup({
    tree = {
        icon_set = "codicons"
    },
    panel = {
        orientation = "left",
        panel_size  = 30
    }
})
```


================================================
FILE: doc/litee.txt
================================================
*litee.nvim* litee.nvim

Author:   Louis DeLosSantos <louis.delos@gmail.com>
Homepage: <https://github.com/ldelossa/litee.nvim>
License:  MIT license

██╗     ██╗████████╗███████╗███████╗   ███╗   ██╗██╗   ██╗██╗███╗   ███╗
██║     ██║╚══██╔══╝██╔════╝██╔════╝   ████╗  ██║██║   ██║██║████╗ ████║ Lightweight
██║     ██║   ██║   █████╗  █████╗     ██╔██╗ ██║██║   ██║██║██╔████╔██║ Integrated
██║     ██║   ██║   ██╔══╝  ██╔══╝     ██║╚██╗██║╚██╗ ██╔╝██║██║╚██╔╝██║ Text
███████╗██║   ██║   ███████╗███████╗██╗██║ ╚████║ ╚████╔╝ ██║██║ ╚═╝ ██║ Editing
╚══════╝╚═╝   ╚═╝   ╚══════╝╚══════╝╚═╝╚═╝  ╚═══╝  ╚═══╝  ╚═╝╚═╝     ╚═╝ Environment
====================================================================================
CONTENTS                                                            *litee-contents*

  1     Intro..............................................|litee-intro|
  2     Usage..............................................|litee-usage|
  3     Library Modules................................|litee-libraries|  
  4     lib/details..................................|litee-lib-details|  
  5     lib/highlights............................|litee-lib-highlights|  
  6     lib/icons......................................|litee-lib-icons|  
  7     lib/jumps......................................|litee-lib-jumps|  
  8     lib/lsp..........................................|litee-lib-lsp|  
  9     lib/navi........................................|litee-lib-navi|  
  10    lib/notify......................................|litee-lib-navi|  
  11    lib/panel......................................|litee-lib-panel|  
  12    lib/state......................................|litee-lib-state|  
  13    lib/tree........................................|litee-lib-tree|  
  14    lib/util........................................|litee-lib-util|  
  15    lib/term........................................|litee-lib-term|  

====================================================================================
INTRODUCTION                                                           *litee-intro*

Litee.nvim (pronounced lite) is a library for building "IDE-lite" experience in Neovim. 

By utilizing the "litee" library plugin authors can achieve a consistent experience
across separate plugins.

There are several official litee plugins which can act as a reference for implementing
additional.

- Calltree
https://github.com/ldelossa/litee-calltree

Analogous to VSCode's "Call Hierarchy" tool, this feature exposes an explorable tree
of incoming or outgoing calls for a given symbol. 

Unlike other Neovim plugins, the tree can be expanded and collapsed to discover 
"callers-of-callers" and "callees-of-callees" until you hit a leaf.

- Symboltree
https://github.com/ldelossa/litee-symboltree

Analogous to VSCode's "Outline" tool, this feature exposes a live tree of document
symbols for the current file. 

The tree is updated as you move around and change files.

- Filetree
https://github.com/ldelossa/litee-filetree

Analogous to VSCode's "Explorer", this feature exposes a full feature file explorer 
which supports recursive copies, recursive moves, and proper renaming of a file 
(more on this in the appropriate section).

====================================================================================
Usage                                                                  *litee-usage*

Litee.nvim exports a single lua module called "lib".

Inside "lib" are several sub-modules which expose a facility for plugin authors.

Each lib will be covered in detail in their respective sections.

The library itself has a config object which configures each sub-module.

The configuration is structured like so (with defaults).
>
    M.config = {
        icons = {},
        jumps = {},
        lsp = {},
        navi = {},
        notify = {
            enabled = true,
        },
        panel = {
            orientation = "left",
            panel_size = 30,
        },
        state = {},
        tree = {
            icon_set = "default",
            indent_guides = true
        }
    }
<
Each key of the configuration corresponds to a library sub-module.

You can apply configuration to litee/lib by way of it's setup method found
in litee/lib/init.lua, for example:
>
    require('litee.lib').setup({
        tree = {
            icon_set = "codicons"
        },
        panel = {
            orientation = "top",
            panel_size  = 15
        }
    })
<
The above overrides the default configuration options for the icon_set used in the
tree sub-module and changes the panel sub-module's orientation and size.

Example for custom icons:
>
    -- Provide a custom icon_set which will be merged with the default icon_set.
    require('litee.lib').setup{
        tree = { icon_set_custom = { Struct = "s" } }
    }

    -- You can even copy, paste the icon_set in `lib/icons/init.lua`, then
    -- modify it and pass it to `icon_set_custom`.
    local icon_set_custom = { ... }
    require('litee.lib').setup{
        tree = { icon_set_custom = icon_set_custom }
    }

    -- Provide a custom icon_set which will be merged with the specified icon_set
    -- from `lib/icons/init.lua` by name.
    require('litee.lib').setup{
        tree = { icon_set_custom = { Struct = "s" }, icon_set = "codicons" }
    }
<
====================================================================================
lib/details                                                      *litee-lib-details*

The `details` library exports a consistent way to display and close a details
pop up window.

The contents of the `details` pop-up is provided by a `detail_func` passed
into the `details_popup` function. 

Thus, the caller can determine what the details are for a particular node or 
plugin element.

The `details` object was designed to be used with a tree node, however passing
in any type for the "node" argument will work as long as the associated "detail_func"
can parse the object and spit out a set of buffer lines.

Use `close_details_popup()` to close the pop-up.

====================================================================================
lib/highlights                                                *litee-lib-highlights*

The `highlights` library defines the highlights used within the `litee` library,
methods for setting up the default highlights, and a sub-module for the 
auto-highlights features.

The following highlights are exported and can be defined for theme overriding.
>
    M.hls = {
        SymbolDetailHL      = "LTSymbolDetail",
        SymbolHL            = "LTSymbol",
        SymbolJumpHL        = "LTSymbolJump",
        SymbolJumpRefsHL    = "LTSymbolJumpRefs",
        IndentGuideHL       = "LTIndentGuide",
        ExpandedGuideHL     = "LTExpandedGuide",
        CollapsedGuideHL    = "LTCollapsedGuide",
        SelectFiletreeHL    = "LTSelectFiletree"
    }
<
The `auto` module provides a facility for highlighting areas of a source file
given a node and a window. 

TODO: The `auto` module should not rely on "lib_util.resolve_absolute_file_path" 
and "lib_util.resolve_location", as these methods require us to understand the 
types of "node" a head of time. 

====================================================================================
lib/icons                                                          *litee-lib-icons*

The `icons` library defines and exports icon sets which plugin authors may use
for a consistent experience. 

Currently `codicons`, `simple`, `nerd` and `default` icons are exported.

The `default` icon set only supplies the stock UTF-8 icons necessary to display
litee's UI such as indent guides and tree symbols.

Users of this library can override the exported icon libraries during runtime to
change an icon from its default.

This library also exports a list of icon highlights which can be overriden.

Check out the source file `lib/icons/init.lua` for full details.

====================================================================================
lib/jumps                                                          *litee-lib-jumps*

The `jumps` library defines and exports functions which perform source file jumps
to a specific "location" object. 

The "location" object is specified by the LSP, see: 
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#location

Highlights can be set within the jumped-to source window and can be cleared with the `set_jump_hl`
method.

TODO: refactor jumps library to no longer need "lib_util.resolve_location" - all location details
should be passed in.

====================================================================================
lib/lsp                                                              *litee-lib-lsp*

The `lsp` library holds methods specific to interacting with the native LSP 
library. 

This includes helpers for making various LSP requests, wrappers for LSP methods
and a library for creating Hover pop-ups.

This is the library to use or contribute to if you need to interface with 
Neovim's native LSP libraries.

====================================================================================
lib/navi                                                            *litee-lib-navi*

The `navi` library is small and exports methods for progressing a cursor forward
or backwards in a window which is registered with litee. 

Two callbacks exist to perform actions before and after the cursor move. 
See source file for details.

See `litee-lib-panel` for information on registration.

====================================================================================
lib/notify                                                          *litee-lib-notify*

The `notify` library produces pop-up notifications at the top right corner
of the editor.

Methods exist to create both persistent notifications and ones with configurable
timeouts, along with methods to close all notifications.

Currently, notifications stack on top of each other so only one is visible at a time.

====================================================================================
lib/panel                                                          *litee-lib-panel*

The `panel` library provides a consistent panel experience across plugins which
utilizes the `litee.nvim` library. 

The panel is akin to panels in JetBrains and VSCode IDEs. 

For a plugin to integrate with the panel it must register itself with the panel
and it also must utilize "lib/state" to store its runtime state.

Runtime state holds information about a registered plugins windows, tab, buffer, 
etc, and is formally defined in `lib/state`

To register a plugin with the panel the `litee.lib.panel.register_component` method
must be used. 

This method requires a `pre_window_create` callback and optionally takes a 
`post_window_create` callback. 

The `pre_window_create` callback must create a buffer for the plugin being 
registered and write the buffer ID into the plugin's component state, which is 
an argument to this callback. The plugin is free to perform any other actions 
associated with displaying its window, such as setting up autocommands or buffer options.

The `post_window_create` method is optional and when called Neovim is inside the 
newly created window within the panel. The plugin is free to perform any in-window
manipulations such as setting syntax highlights or window options. 

The panel also supports a feature dubbed "PopOut" panels. 

"PopOut" panels are floating windows which act as if you're "popping out" the 
panel window to a float, and will "pop" back into the panel when closed. 
This is convenient for "zooming" into panel windows. 

Additionally, the panel need not be visible for a "PopOut" panel to be displayed.
Meaning, users of `litee.nvim` do not necessary need to interface with the panel, 
and can use only "PopOut" panels if they prefer, tho the plugin has to facilitate 
this by calling the right `lib/panel` api functions.

For more info on "PopOut" panels see the "popout_to" function in `litee.lib.panel`.

The rest of the API footprint exists to display/hide/jump into the panel. 
See the source code for full details.

====================================================================================
lib/state                                                          *litee-lib-state*

The `state` library provides a library for handling plugin state.

Litee must keep track of when components (plugins) are displayed in the panel, 
if their windows are valid, if they have an associated tree handle, whether their
buffer is valid, etc... 

Likewise, plugins need a way to retrieve and store their own state in between 
function calls.

The `state` library acts a registry for this state and makes it retrievable both
globally and by components.

A component should only mutate its own state, unless it positively knows what 
its doing. 

The state structure looks as follows:
>
  {
      "componentA" = {
          buf = 0,
          win = 0,
          tab = 0,
          tree = 0,
          win_dimensions = {0, 0},
          invoking_win = 0,
          active_lsp_clients = {list of lsp clients},
          (component specific fields)...
      },
      "componentB" = {
          buf = 0,
          win = 0,
          tab = 0,
          tree = 0,
          win_dimensions = {0, 0},
          invoking_win = 0,
          active_lsp_clients = {list of lsp clients},
          (component specific fields)...
      }
  }
<
When functions expect the full state the function parameter is typically "state" and when
functions expect a component's stat (state["componentA"] for example) the parameter
is typically "component_state". 

Ideally all of a plugin's methods which interface with litee require a "component_state", 
and they should only touch their own state.

Accessors methods for both global and component state exist in `lib/state` along with methods
to write both types of state back to the registry.

Neovim is single threaded and tables are references, so its actually pretty uncommon to
write state back into the registry. The exception is when setting the initial component
state table in the global state table, performed by `put_component_state`

`lib/state.lua` exports some helpful methods such as getting the component type for
a particular buffer ID. Like always, until I have time to document better, check out the
source for full details.

====================================================================================
lib/tree                                                            *litee-lib-tree*

The `tree` library implements a reusable tree which supports the expansion and 
collapsing of nodes. 

A node in the tree has a core data structure which a plugin can tag on plugin-specific
data on. 

A node looks as follows and can be instantiated with the "lib.tree.node.new_node()"
method.
>
  {
      -- a non-unique display name for the node
      name = name,
      -- the depth of the node in the target tree
      depth = depth,
      -- a unique key used to identify the node when
      -- placed into a tree
      key = key,
      -- a list of children nodes with recursive definitions.
      children = {},
      -- whether this node is expanded in its containing
      -- tree.
      expanded = false,
  }
<
Its the caller's job to define each value ensuring the key for the node is unique within
the tree being built. 

The `tree` lib itself is a registry where you request a tree and get back a handle to it.

The handle can be stored on a plugin's state object and stored in `lib/state` and it also
passed to `lib/tree` methods to identify which tree is being acted upon.

The data structure which represents a tree looks like this:
`{root = {}, depth_table = {}, kind = "", source_line_map = nil, buf_line_map = nil}`

Where root is an empty root node, depth_table is a flattened 2d array containing a list of nodes
at a particular depth of the tree (useful for quick lookups), kind is the kind of tree defined
by the caller, source_line_map is a mapping from a source code line to a node in the tree, and
buf_line_map is a mapping from a buffer line in the tree to a source code line.

source_line_map can only be realized if your node has a top level "location" key with an LSP
specified `location` structure as its value. 

Both aforementioned maps make it possibe to map items in the tree to source code lines and 
vice versa. The best way to understand this is looking at the reference implementations of
"litee-filetree", "litee-calltree", and "litee-symboltree".

Once a tree is created you can begin building its nodes. 

A tree is build by creating a root node and then a list of children.

For convenience, the `add_node` function will take a root and a list of children,
compute the children's depth, attach the children to the root, and add it to the tree.

It's important to understand that by using the `add_node` without further options, you
do not need to worry about the children node's depth fields, but you DO need to always
set the root's depth field.

When the `add_node` method receives a root node with its depth field of 0 it throws
away the old tree and creates a new one. 

When the `add_node` method receives a root node with a depth greater then zero it can
compute its children's depths and will add this new root (of a sub-tree) to the existing
tree at the appropriate depth.

Sometimes, the caller wants to build the entire tree with their own business logic and
simply use the `tree` library for marshaling into a Neovim buffer and other facilities 
such as expand and collapsing. If this is the case you can use the `external` flag 
to the 'add_node' method. 

When the `add_node` method sees the external flag is set to true, it performs no 
actions on the root and simply adds it to the tree structure outlined above. The
`children` parameter is completely ignored.

Once the tree is built and all the desired nodes are added, you can write the tree
to a buffer with the "write_tree" method. 

`function M.write_tree(buf, tree, marshal_func, no_guide_leaf)`

The write_tree method takes a buffer ID to write too, a tree ID to write, a marshal_func
which is called for each node and returns the necessary strings which will make up the 
buffer line in the tree, and a "no_guide_leaf" flag. See the method's documentation
for marshal_func details.

The `no_guide_leaf` flag tells the `write_tree` method that when a node is expanded,
and it has no children, leave off the "expanded" guide (the down arrow showing its expanded). 

This is a nice effect for some trees and a helper method exists if your plugin will always
use this method `function M.write_tree_no_guide_leaf(buf, tree, marshal_func)`. 

Make note, the `write_tree` function can only determine a leaf *after* the node is expanded,
for example, a node is collapsed, you expand it, it has no children, no expanded guide is shown.

There are times where the caller can determine an item is a leaf *before* its expanded, for example,
in a file tree, we know a regular file does not need an expand guide. 

To accomplish this the `marshal_func` suports returning an override for the expand guide as its 
very last argument. If returned, this symbol is used instead of the expand guide `write_tree` 
would use on its own accord. `litee-filetree` uses this to simply return a " " when it sees
a regular file.

There is a method, `function M.marshal_line(linenr, handle)', which takes a tree buffer's linenr
and a tree handle and returns the corresponding node.

A small note on the depth_table. A depth_table is a flattened 2d array which hold a list of nodes
at a particular depth. This makes getting nodes at a particular depth very easy and (maybe...?) 
faster then a tree traversal. A depth_table is available after any initial and all subsequent
`add_node` calls.

Various methods exist in the library for manipulating the tree such as collapsing nodes and 
removing subtrees. Take a look at the source code to see what is available.

====================================================================================
lib/util                                                            *litee-lib-util*

Lib `util` is a dumping ground for various helper functions and utilities. 

Lib `util` exports several helpful sub-libraries. 

`lib.util.window` For helper functions around Neovim windows
`lib.util.buffer` For helper functions around Neovim buffers
`lib.util.path`   For helper functions dealing with file system paths (only linux right now.)

====================================================================================
lib/term                                                            *litee-lib-term*

Lib `term` exports a method for opening a Neovim native terminal that is aware
of `litee.nvim` environment. 

This terminal can be opened on the top or bottom and is controlled by the "term"
configuration block in the `lib.config` module.

>
    term = {
        -- can be  "top" or "bottom"
        position = "bottom",
        -- the initial size of the terminal
        term_size = 15,
        -- if true maps arrow keys to window resize
        -- commands.
        map_resize_keys = true,
    },
<

The terminal creates two "terminal" mode key bindings. 
>
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>v", "<cmd>lua require('configs.terminal').terminal_vsplit()<cr>", opts)

    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>n", "<C-\\><C-n>", opts)

    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>h", "<C-\\><C-n> <C-w>h", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>j", "<C-\\><C-n> <C-w>j", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>k", "<C-\\><C-n> <C-w>k", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>l", "<C-\\><C-n> <C-w>l", opts)
<
The first one will open another terminal in a vsplit relative to the terminal you're issuing
the command in.

The second is a helper that puts your terminal back into normal mode. 

The final set are short-cuts for jumping out of the terminal into other windows.

Be aware, these mappins will only work when your Vim mode is "terminal" which is when
input is being forwarded directly to the shell. If you are in normal mode (the shell is just
a buffer of lines at that point) the mappins will revert back to normal mode mappings.

The term can be triggered open with the "LTTerm" user command.

vim:ft=help


================================================
FILE: doc/tags
================================================
after	litee.txt	/*after*
before	litee.txt	/*before*
litee-contents	litee.txt	/*litee-contents*
litee-intro	litee.txt	/*litee-intro*
litee-lib-details	litee.txt	/*litee-lib-details*
litee-lib-highlights	litee.txt	/*litee-lib-highlights*
litee-lib-icons	litee.txt	/*litee-lib-icons*
litee-lib-jumps	litee.txt	/*litee-lib-jumps*
litee-lib-lsp	litee.txt	/*litee-lib-lsp*
litee-lib-navi	litee.txt	/*litee-lib-navi*
litee-lib-notify	litee.txt	/*litee-lib-notify*
litee-lib-panel	litee.txt	/*litee-lib-panel*
litee-lib-state	litee.txt	/*litee-lib-state*
litee-lib-term	litee.txt	/*litee-lib-term*
litee-lib-tree	litee.txt	/*litee-lib-tree*
litee-lib-util	litee.txt	/*litee-lib-util*
litee-usage	litee.txt	/*litee-usage*
litee.nvim	litee.txt	/*litee.nvim*


================================================
FILE: lua/litee/lib/commands.lua
================================================
local M = {}

-- commands will setup any Vim commands exported on litee.lib
-- setup.
function M.setup()
    vim.cmd("command! LTPanel           lua require('litee.lib.panel').toggle_panel()")
    vim.cmd("command! LTTerm            lua require('litee.lib.term').terminal()")
    vim.cmd("command! LTListTerms       lua require('litee.lib.term').list_terminals()")
    vim.cmd("command! LTClearJumpHL     lua require('litee.lib.jumps').set_jump_hl(false)")
    vim.cmd("command! LTClosePanelPopOut lua require('litee.lib.panel').close_current_popout()")
end

return M


================================================
FILE: lua/litee/lib/config.lua
================================================
local M = {}

-- config is a global configuration object
-- for each module in the litee library.
--
-- config for a particular module is keyed
-- by the module's directory name.
M.config = {
    icons = {},
    jumps = {},
    lsp = {},
    navi = {},
    notify = {
        enabled = true,
    },
    panel = {
        orientation = "left",
        panel_size = 30,
    },
    state = {},
    term = {
        position = "bottom",
        term_size = 15,
        map_resize_keys = true,
    },
    tree = {
        icon_set = "default",
        icon_set_custom = nil,
        indent_guides = true
    }
}

return M


================================================
FILE: lua/litee/lib/details/init.lua
================================================
local M = {}

-- a singleton float window for a details popup.
local float_win = nil

-- close_details_popups closes the created popup window
-- if it exists.
function M.close_details_popup()
    if float_win ~= nil and
        vim.api.nvim_win_is_valid(float_win) then
        vim.api.nvim_win_close(float_win, true)
        float_win = nil
    end
end

-- details_popup creates a popup window showing futher details
-- about a symbol.
--
-- @param state (table) The global state as defined by
-- the lib/state library.
-- @param node (table) A node passed to `detail_func` representing
-- the item being described.
-- @param detail_func function(state, node) A function called with the
-- provided state and node that returns a list of buffer lines.
-- The function must evaluate both arguments and return a list of buffer
-- lines which describe any details about the node the caller defines.
function M.details_popup(state, node, detail_func)
    local buf = vim.api.nvim_create_buf(false, true)
    if buf == 0 then
        vim.api.nvim_err_writeln("details_popup: could not create details buffer")
        return
    end
    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'delete')
    vim.api.nvim_buf_set_option(buf, 'syntax', 'yaml')

    local lines = detail_func(state, node)
    if lines == nil then
        return
    end

    local width = 20
    for _, line in ipairs(lines) do
        local line_width = vim.fn.strdisplaywidth(line)
        if line_width > width then
            width = line_width
        end
    end

    vim.api.nvim_buf_set_option(buf, 'modifiable', true)
    vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)
    vim.api.nvim_buf_set_option(buf, 'modifiable', false)
    local popup_conf = vim.lsp.util.make_floating_popup_options(
            width,
            #lines,
            {
                border= "rounded",
                focusable= false,
                zindex = 99,
            }
    )
    float_win = vim.api.nvim_open_win(buf, false, popup_conf)
end

return M


================================================
FILE: lua/litee/lib/highlights/auto.lua
================================================
local lib_util  = require('litee.lib.util')
local lib_hi    = require('litee.lib.highlights')

local M = {}

-- the current highlight used for auto-highlighting
M.higlight_ns = vim.api.nvim_create_namespace("calltree-hl")

-- highlight will set a highlight on the source code
-- lines the provided node represents if the invoking_win
-- holds a buffer to said file.
--
-- @param node (table) The element representing a source
-- code symbol or element. This function requires the node
-- to have a top level ".location" field.
-- @param set (bool) If false any highlights which were
-- previously set are cleared. If true, highlights will
-- be created.
-- @param win (int) A window handle to the window
-- being evaluated for highlighting.
function M.highlight(node, set, win)
    if not vim.api.nvim_win_is_valid(win) then
        return
    end
    local buf = vim.api.nvim_win_get_buf(win)
    if not vim.api.nvim_buf_is_valid(buf) then
        return
    end
    vim.api.nvim_buf_clear_namespace(
        buf,
        M.higlight_ns,
        0,
        -1
    )
    if not set then
        return
    end

    local location = node.location
    if location == nil then
        return
    end
    local range = location.range

    if range["end"] == nil then
        return
    end

    -- make sure URIs match before setting highlight
    local invoking_buf = vim.api.nvim_win_get_buf(win)
    local cur_file = vim.api.nvim_buf_get_name(invoking_buf)
    local symbol_path = lib_util.absolute_path_from_uri(location.uri)
    if cur_file ~= symbol_path then
        return
    end

    vim.api.nvim_buf_add_highlight(
        buf,
        M.higlight_ns,
        lib_hi.hls.SymbolJumpHL,
        range["start"].line,
        range["start"].character,
        range["end"].character
    )
    vim.api.nvim_win_set_cursor(win, {range["start"].line+1, 0})
end

return M


================================================
FILE: lua/litee/lib/highlights/init.lua
================================================
local M = {}

-- hls is a map of UI specific highlights used
-- by the litee.nvim library.
M.hls = {
    SymbolDetailHL      = "LTSymbolDetail",
    SymbolHL            = "LTSymbol",
    SymbolJumpHL        = "LTSymbolJump",
    SymbolJumpRefsHL    = "LTSymbolJumpRefs",
    IndentGuideHL       = "LTIndentGuide",
    ExpandedGuideHL     = "LTExpandedGuide",
    CollapsedGuideHL    = "LTCollapsedGuide",
    SelectFiletreeHL    = "LTSelectFiletree",
    NormalSB            = "LTNormalSB"
}

-- setup_default_highlights configures a list of default
-- highlights for the litee.nvim library.
function M.setup_default_highlights()
    local dark = {
        LTBoolean              = 'hi LTBoolean                guifg=#0087af guibg=None',
        LTConstant             = 'hi LTConstant               guifg=#0087af guibg=None',
        LTConstructor          = 'hi LTConstructor            guifg=#4DC5C6 guibg=None',
        LTField                = 'hi LTField                  guifg=#0087af guibg=None',
        LTFunction             = 'hi LTFunction               guifg=#988ACF guibg=None',
        LTMethod               = 'hi LTMethod                 guifg=#0087af guibg=None',
        LTNamespace            = 'hi LTNamespace              guifg=#87af87 guibg=None',
        LTNumber               = 'hi LTNumber                 guifg=#9b885c guibg=None',
        LTOperator             = 'hi LTOperator               guifg=#988ACF guibg=None',
        LTParameter            = 'hi LTParameter              guifg=#988ACF guibg=None',
        LTParameterReference   = 'hi LTParameterReference     guifg=#4DC5C6 guibg=None',
        LTString               = 'hi LTString                 guifg=#af5f5f guibg=None',
        LTSymbol               = 'hi LTSymbol                 guifg=#87afd7 ',
        LTSymbolDetail         = 'hi LTSymbolDetail           ctermfg=024 cterm=italic guifg=#988ACF gui=italic',
        LTSymbolJump           = 'hi LTSymbolJump             ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#87afd7 gui=italic,bold',
        LTSymbolJumpRefs       = 'hi LTSymbolJumpRefs         ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#9b885c gui=italic,bold',
        LTType                 = 'hi LTType                   guifg=#9b885c guibg=None',
        LTURI                  = 'hi LTURI                    guifg=#988ACF guibg=None',
        LTIndentGuide          = 'hi LTIndentGuide            guifg=None    guibg=None',
        LTExpandedGuide        = 'hi LTExpandedGuide          guifg=None    guibg=None',
        LTCollapsedGuide       = 'hi LTCollapsedGuide         guifg=None    guibg=None',
        LTSelectFiletree       = 'hi LTSelectFiletree ctermbg=131  ctermfg=246 cterm=None guibg=#af5f5f guifg=#e4e4e4 gui=None'
    }
    local light = {
        LTBoolean               = 'hi LTBoolean                guifg=#005f87 guibg=None',
        LTConstant              = 'hi LTConstant               guifg=#005f87 guibg=None',
        LTConstructor           = 'hi LTConstructor            guifg=#9b885c guibg=None',
        LTField                 = 'hi LTField                  guifg=#005f87 guibg=None',
        LTFunction              = 'hi LTFunction               guifg=#806CCF guibg=None',
        LTMethod                = 'hi LTMethod                 guifg=#005f87 guibg=None',
        LTNamespace             = 'hi LTNamespace              guifg=#87af87 guibg=None',
        LTNumber                = 'hi LTNumber                 guifg=#9b885c guibg=None',
        LTOperator              = 'hi LTOperator               guifg=#806CCF guibg=None',
        LTParameter             = 'hi LTParameter              guifg=#806CCF guibg=None',
        LTParameterReference    = 'hi LTParameterReference     guifg=#268889 guibg=None',
        LTString                = 'hi LTString                 guifg=#af5f5f guibg=None',
        LTSymbol                = 'hi LTSymbol                 guifg=#806CCF gui=underline',
        LTSymbolDetail          = 'hi LTSymbolDetail           ctermfg=024 cterm=italic guifg=#005f87 gui=italic',
        LTSymbolJump            = 'hi LTSymbolJump             ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#87afd7 gui=italic,bold',
        LTSymbolJumpRefs        = 'hi LTSymbolJumpRefs         ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#9b885c gui=italic,bold',
        LTType                  = 'hi LTType                   guifg=#268889 guibg=None',
        LTURI                   = 'hi LTURI                    guifg=#806CCF guibg=None',
        LTIndentGuide           = 'hi LTIndentGuide            guifg=None    guibg=None',
        LTExpandedGuide         = 'hi LTExpandedGuide          guifg=None    guibg=None',
        LTCollapsedGuide        = 'hi LTCollapsedGuide         guifg=None    guibg=None',
        LTSelectFiletree        = 'hi LTSelectFiletree ctermbg=131  ctermfg=246 cterm=None guibg=#af5f5f guifg=#e4e4e4 gui=None'
    }
    local bg = vim.api.nvim_get_option("background")
    if bg == "dark" then
        for hl_name, hl in pairs(dark) do
            if vim.fn.hlexists(hl_name) == 0 then
                vim.cmd(hl)
            end
        end
    end
    if bg == "light" then
        for hl_name, hl in pairs(light) do
            if vim.fn.hlexists(hl_name) == 0 then
                vim.cmd(hl)
            end
        end
    end
end

return M


================================================
FILE: lua/litee/lib/icons/init.lua
================================================
local M = {}

-- a lot of these are yoinked from:
-- https://github.com/onsails/lspkind-nvim/blob/master/lua/lspkind/init.lua
M.nerd = {
    Account         = '',
    Array           = "",
    Bookmark        = "",
    Boolean         = "",
    Calendar        = '',
    Check           = '',
    CheckAll        = '',
    Circle          = '',
    CircleFilled    = '',
    CirclePause     = '',
    CircleSlash     = '',
    CircleStop      = '',
    Class           = "ﴯ",
    Collapsed       = "",
    Color           = "",
    Comment         = '',
    Constant        = "",
    Constructor     = "",
    DiffAdded       = '',
    Enum            = "",
    EnumMember      = "",
    Event           = "",
    Expanded        = "",
    Field           = "ﰠ",
    File            = "",
    Folder          = "",
    Function        = "",
    GitBranch       = '',
    GitCommit       = 'ﰖ',
    GitCompare      = '',
    GitIssue        = '',
    GitMerge        = 'שּׁ',
    GitPullRequest  = '',
    GitRepo         = '',
    IndentGuide     = "⎸",
    Info            = '',
    Interface       = "",
    Key             = "",
    Keyword         = "",
    Method          = "",
    Module          = "",
    MultiComment    = '',
    Namespace       = "",
    Notebook        = "ﴬ",
    Null            = "ﳠ",
    Number          = "",
    Object          = "",
    Operator        = "",
    Package         = "",
    Pass            = '',
    PassFilled      = '',
    Pencil          = '',
    Property        = "ﰠ",
    Reference       = "",
    Separator       = "•",
    Snippet         = "",
    Space           = " ",
    String          = "",
    Struct          = "פּ",
    Text            = "",
    TypeParameter   = "",
    Unit            = "塞",
    Value           = "",
    Variable        = "",
}

M.codicons = {
    Account         = '',
    Array           = "",
    Bookmark        = "",
    Boolean         = "",
    Calendar        = '',
    Check           = '',
    CheckAll        = '',
    Circle          = '',
    CircleFilled    = '',
    CirclePause     = '',
    CircleSlash     = '',
    CircleStop      = '',
    Class           = "",
    Collapsed       = "",
    Color           = "",
    Comment         = '',
    CommentExclaim  = '',
    Constant        = "",
    Constructor     = "",
    DiffAdded       = '',
    Enum            = "",
    EnumMember      = "",
    Event           = "",
    Expanded        = "",
    Field           = "",
    File            = "",
    Folder          = "",
    Function        = "",
    GitBranch       = '',
    GitCommit       = '',
    GitCompare      = '',
    GitIssue        = '',
    GitMerge        = '',
    GitPullRequest  = '',
    GitRepo         = '',
    History         = '',
    IndentGuide     = "⎸",
    Info            = '',
    Interface       = "",
    Key             = "",
    Keyword         = "",
    Method          = "",
    Module          = "",
    MultiComment    = '',
    Namespace       = "",
    Notebook        = "",
    Notification    = '',
    Null            = "",
    Number          = "",
    Object          = "",
    Operator        = "",
    Package         = "",
    Pass            = '',
    PassFilled      = '',
    Pencil          = '',
    Property        = "",
    Reference       = "",
    RequestChanges  = '',
    Separator       = "•",
    Snippet         = "",
    Space           = " ",
    String          = "",
    Struct          = "",
    Sync            = '',
    Text            = "",
    TypeParameter   = "",
    Unit            = "",
    Value           = "",
    Variable        = "",
}

M.default = {
    Account         = "🗣",
    Array           = "\\[\\]",
    Bookmark        = "🏷",
    Boolean         = "∧",
    Calendar        = '🗓',
    Check           = '✓',
    CheckAll        = '🗸🗸',
    Circle          = '🞆',
    CircleFilled    = '●',
    CirclePause     = '⦷',
    CircleSlash     = '⊘',
    CircleStop      = '⦻',
    Class           = "c",
    Collapsed       = "▶",
    Color           = "🖌",
    Comment         = '🗩',
    CommentExclaim  = '🗩',
    Constant        = "c",
    Constructor     = "c",
    DiffAdded       = '+',
    Enum            = "Ε",
    EnumMember      = "Ε",
    Event           = "🗲",
    Expanded        = "▼",
    Field           = "𝐟",
    File            = "🗀",
    Folder          = "🗁",
    Function        = "ƒ",
    GitBranch       = ' ',
    GitCommit       = '⫰',
    GitCompare      = '⤄',
    GitIssue        = '⊙',
    GitMerge        = '⫰',
    GitPullRequest  = '⬰',
    GitRepo         = '🕮',
    History         = '⟲',
    IndentGuide     = "⎸",
    Info            = '🛈',
    Interface       = "I",
    Key             = "",
    Keyword         = "",
    Method          = "",
    Module          = "M",
    MultiComment    = '🗩',
    Namespace       = "N",
    Notebook        = "🕮",
    Notification    = '🕭',
    Null            = "null",
    Number          = "#",
    Object          = "{}",
    Operator        = "0",
    Package         = "{}",
    Pass            = '🗸',
    PassFilled      = '🗸',
    Pencil          = '',
    Property        = "🛠",
    Reference       = "⛉",
    RequestChanges  = '⨪',
    Separator       = "•",
    Space           = " ",
    String          = "\"",
    Struct          = "struct",
    Sync            = '🗘',
    Text            = "\"",
    TypeParameter   = "T",
    Unit            = "U",
    Value           = "v",
    Variable        = "V",
}

M.simple = {
    Account         = "A",
    Array           = "\\[\\]",
    Bookmark        = "BM",
    Boolean         = "bool",
    Calendar        = 'cal',
    Check           = 'x',
    CheckAll        = 'xx',
    Circle          = 'o',
    CircleFilled    = 'O',
    CirclePause     = 'P',
    CircleSlash     = 'ø',
    CircleStop      = 'stop',
    Class           = "class",
    Collapsed       = ">",
    Color           = "color",
    Comment         = 'c',
    CommentExclaim  = 'c!',
    Constant        = "c",
    Constructor     = "C",
    DiffAdded       = '+',
    Enum            = "Ε",
    EnumMember      = "Ε",
    Event           = "e",
    Expanded        = "v",
    Field           = "f",
    File            = "F",
    Folder          = "D",
    Function        = "fn",
    GitBranch       = 'br',
    GitCommit       = 'ci',
    GitCompare      = 'cmp',
    GitIssue        = 'I',
    GitMerge        = 'M',
    GitPullRequest  = 'PR',
    GitRepo         = 'R',
    History         = 'H',
    IndentGuide     = " ",
    Info            = 'i',
    Interface       = "I",
    Key             = "k",
    Keyword         = "kw",
    Method          = "m",
    Module          = "M",
    MultiComment    = '#',
    Namespace       = "NS",
    Notebook        = "NB",
    Notification    = 'N',
    Null            = "null",
    Number          = "#",
    Object          = "{}",
    Operator        = "op",
    Package         = "{}",
    Pass            = 'y',
    PassFilled      = 'yy',
    Pencil          = 'e',
    Property        = "P",
    Reference       = "&",
    RequestChanges  = '-',
    Separator       = ".",
    Space           = " ",
    String          = "\"",
    Struct          = "S",
    Sync            = 's',
    Text            = "\"",
    TypeParameter   = "T",
    Unit            = "U",
    Value           = "v",
    Variable        = "V",
}

M.icon_hls = {
    Array           = "LTConstant",
    Boolean         = "LTBoolean",
    Class           = "LTType",
    Constant        = "LTConstant",
    Constructor     = "LTFunction",
    Enum            = "LTType",
    EnumMember      = "LTField",
    Event           = "LTType",
    Field           = "LTField",
    File            = "LTURI",
    Folder          = "LTNamespace",
    Function        = "LTFunction",
    Interface       = "LTType",
    Key             = "LTType",
    Keyword         = "LTConstant",
    Method          = "LTFunction",
    Module          = "LTNamespace",
    Namespace       = "LTNamespace",
    Null            = "LTType",
    Number          = "LTNumber",
    Object          = "LTType",
    Operator        = "LTOperator",
    Package         = "LTNamespace",
    Property        = "LTMethod",
    Reference       = "LTType",
    Snippet         = "LTString",
    String          = "LTString",
    Struct          = "LTType",
    Text            = "LTString",
    TypeParameter   = "LTParameter",
    Unit            = "LTType",
    Value           = "LTType",
    Variable        = "LTConstant",

    Info            = 'LTInfo',
    Pass            = 'LTSuccess',
    PassFilled      = 'LTSuccess',
    Account         = 'LTAccount',
    Check           = 'LTSuccess',
    CheckAll        = 'LTSuccess',
    CircleFilled    = 'LTDefault',
    Circle          = 'LTDefault',
    CircleSlash     = 'LTWarning',
    GitCompare      = 'LTGitCompare',
    GitBranch       = 'LTGitBranch',
    GitPullRequest  = 'LTGitPullRequest',
    CircleStop      = 'LTFailure',
    DiffAdded       = 'LTDiffAdded',
    CirclePause     = 'LTWarning',
    GitCommit       = 'LTGitCommit',

    Comment         = 'LTComment',
    MultiComment    = 'LTMultiComment',

    Calendar        = 'LTDefault',
    Pencil          = 'LTWarning',

    History         = 'LTWarning',
    Sync            = 'LTWarning',
    CommentExclaim  = 'LTWarning',
    RequestChanges  = 'LTFailure',
    Notification    = 'LTDiffAdded'
}

return M


================================================
FILE: lua/litee/lib/init.lua
================================================
local commands = require('litee.lib.commands')
local config = require('litee.lib.config').config
local lib_hi = require('litee.lib.highlights')
local lib_icons = require('litee.lib.icons')

local M = {}

-- Once set up, `M.icon_set` must be a non-nil table.
M.icon_set = nil

local function icon_set()
    local tree = config.tree
    local base = lib_icons[tree.icon_set] or lib_icons["default"]
    local icon_set = nil
    if tree.icon_set_custom ~= nil then
        icon_set = tree.icon_set_custom
        -- merge custom icon with the default
        for key, val in pairs(base) do
            icon_set[key] = icon_set[key] or base[key]
        end
    else
        icon_set = base
    end
    M.icon_set = icon_set
end

-- If a custom icon_set (table) is provided by the user,
-- `M.icon_set` will be updated and returned.
-- A user can use the icons from `lib_icons`
-- via providing a key name instead of a custom icon_set (table).
-- When both arguments are provided, the custom icon_set is merged
-- with the icons given by its name from `lib_icons`.
function M.icon_set_update(custom, icon_key)
    local icon_set = nil
    if custom ~= nil then
        icon_set = icon_key and lib_icons[icon_key] or M.icon_set
        for key, val in pairs(custom) do
            icon_set[key] = custom[key]
        end
    else
        icon_set = lib_icons[icon_key] or lib_icons["default"]
    end
    return icon_set
end

local function merge_subconfig(component, user_subconfig)
    local subconfig = config[component]
    if subconfig == nil then
        return
    end

    for key, val in pairs(user_subconfig) do
        subconfig[key] = val
    end
end

function M.setup(user_config)
    if user_config ~= nil then
        for component, user_subconfig in pairs(user_config) do
            merge_subconfig(component, user_subconfig)
        end
    end

    -- setup icon_set
    icon_set()

    -- setup default highlights
    lib_hi.setup_default_highlights()

    -- setup commands
    commands.setup()

    -- au to close popup with cursor moves or buffer is closed.
    vim.cmd("au CursorMoved,BufWinLeave,WinLeave * lua require('litee.lib.util.buffer').close_all_popups()")

    -- on resize cycle the panel to re-adjust window sizes.
    vim.cmd("au VimResized * lua require('litee.lib.panel.autocmds').on_resize()")

    -- will clean out any tree data for a tab when closed. only necessary
    vim.cmd([[au TabClosed * lua require('litee.lib.state.autocmds').on_tab_closed(vim.fn.expand('<afile>'))]])
end

return M


================================================
FILE: lua/litee/lib/jumps/init.lua
================================================
local config    = require('litee.lib.config').config
local lib_hi    = require('litee.lib.highlights')
local lib_panel = require('litee.lib.panel')

local M = {}

-- the current highlight source, reset on jumps
M.jump_higlight_ns = vim.api.nvim_create_namespace("calltree-jump")
-- the buffer we highlighted last.
M.last_highlighted_buffer = nil

-- move_or_create will a attempt to move from the
-- calltree ui window to the nearest editor window
--
-- if the move fails, assumingly because no other window
-- exists, a new window will be created.
--
-- @param orientation (string) The orientation of the
-- surrouning plugin UI to make jumps intuitive.
-- This is typically the orientation of the litee.nvim
-- panel. Valid arguments are "left, right, top, bottom".
local function move_or_create(orientation)
    local cur_win = vim.api.nvim_get_current_win()
    if orientation == "left" then
        vim.cmd('wincmd l')
    elseif orientation == "right" then
        vim.cmd('wincmd h')
    elseif orientation == "top" then
        vim.cmd('wincmd j')
    elseif orientation == "bottom" then
        vim.cmd('wincmd k')
    end
    if cur_win == vim.api.nvim_get_current_win() then
        if orientation == "left" then
            vim.cmd("botright vsplit")
            return true
        elseif orientation == "right" then
            vim.cmd("topleft vsplit")
            return true
        elseif orientation == "top" then
            vim.cmd("topleft split")
            return true
        elseif orientation == "bottom" then
            vim.cmd("topleft split")
            return true
        end
    end
    return false
end

-- jump_tab will open a new tab then jump to the symbol
--
-- @param location (table) A location object as defined by
-- the LSP.
-- @param node (table) An element which is being jumped to,
-- if this element has a high level "references" field with
-- more "Location" objects, they will be highlighted as well.
function M.jump_tab(location, node, offset_encoding)
    M.set_jump_hl(false, nil)
    vim.cmd("tabedit " .. location.uri)
    vim.cmd("set nocursorline")
    -- if the panel currently has a component "popped-out"
    -- close it before jumping.
    lib_panel.close_current_popout()
    vim.lsp.util.jump_to_location(location, offset_encoding or "utf-8")
    M.set_jump_hl(true, node)
end

-- jump_split will open a new split then jump to the symbol
--
-- @param split (string) The type of split, valid arguments
-- are "split" or "vsplit".
-- @param location (table) A location object as defined by
-- the LSP.
-- @param node (table) An element which is being jumped to,
-- if this element has a high level "references" field with
-- more "Location" objects, they will be highlighted as well.
function M.jump_split(split, location, node, offset_encoding)
    M.set_jump_hl(false, nil)
    if not move_or_create(config["panel"].orientation) then
        vim.cmd(split)
    end
    -- if the panel currently has a component "popped-out"
    -- close it before jumping.
    lib_panel.close_current_popout()
    vim.lsp.util.jump_to_location(location, offset_encoding or "utf-8")
    M.set_jump_hl(true, node)
end

-- jump_neighbor will jump to the symbol using the
-- closest left or right window.
--
-- a window will be created if it does not exist.
--
-- @param location (table) A location object as defined by
-- the LSP.
-- @param node (table) An element which is being jumped to,
-- if this element has a high level "references" field with
-- more "Location" objects, they will be highlighted as well.
function M.jump_neighbor(location, node, offset_encoding)
    M.set_jump_hl(false, nil)
    move_or_create(config["panel"].orientation)
    -- if the panel currently has a component "popped-out"
    -- close it before jumping.
    lib_panel.close_current_popout()
    vim.lsp.util.jump_to_location(location, offset_encoding or "utf-8")
    M.set_jump_hl(true, node)

    -- cleanup any [No Name] buffers if they exist
    for _, buf in ipairs(vim.api.nvim_list_bufs()) do
        local name = vim.api.nvim_buf_get_name(buf)
        if name == "" then
            vim.api.nvim_buf_delete(buf, {force=true})
        end
    end
end

-- jump_invoking will jump to the symbol using the
-- window that initially invoked the calltree.
--
-- a window is created and seen as the new invoking window
-- if the original invoking window has been closed.
--
-- @param location (table) A location object as defined by
-- the LSP.
-- @param win (int) A window handle of the invoking window
-- to jump to.
-- @param node (table) An element which is being jumped to,
-- if this element has a high level "references" field with
-- more "Location" objects, they will be highlighted as well.
function M.jump_invoking(location, win, node, offset_encoding)
    M.set_jump_hl(false, nil)
    if not vim.api.nvim_win_is_valid(win) then
        if config["panel"].orientation == "left" then
            vim.cmd("botright vsplit")
        elseif config["panel"].orientation == "right" then
            vim.cmd("topleft vsplit")
        elseif config["panel"].orientation == "top" then
            vim.cmd("topleft split")
        elseif config["panel"].orientation == "bottom" then
            vim.cmd("topleft split")
        end
        win = vim.api.nvim_get_current_win()
    end
    vim.api.nvim_set_current_win(win)

    -- if the panel currently has a component "popped-out"
    -- close it before jumping.
    lib_panel.close_current_popout()
    vim.lsp.util.jump_to_location(location, offset_encoding or "utf-8")
    M.set_jump_hl(true, node)

    -- cleanup any [No Name] buffers if they exist
    for _, buf in ipairs(vim.api.nvim_list_bufs()) do
        local name = vim.api.nvim_buf_get_name(buf)
        if name == "" then
            vim.api.nvim_buf_delete(buf, {force=true})
        end
    end

    return win
end

-- set_jump_hl will highlight the symbol and
-- any references to the symbol if set == true.
--
-- @param set (bool) If false highlights any previously created
-- jump highlights will be removed.
--
-- @param node (table) An element which is being jumped to,
-- the node must have a high level ".location" field.
-- if this element has a high level ".references" field with
-- an array of "Range" objects (specified by LSP),
-- they will be highlighted as well.
function M.set_jump_hl(set, node)
    if not set then
        if
            M.last_highlighted_buffer ~= nil
            and vim.api.nvim_buf_is_valid(M.last_highlighted_buffer)
        then
            vim.api.nvim_buf_clear_namespace(
                M.last_highlighted_buffer,
                M.jump_higlight_ns,
                0,
                -1
            )
        end
        return
    end

    M.last_highlighted_buffer = vim.api.nvim_get_current_buf()

    -- set highlght for function itself
    local location = node.location
    if location == nil then
        return
    end
    local range = location.range

    vim.api.nvim_buf_add_highlight(
        M.last_highlighted_buffer,
        M.jump_higlight_ns,
        lib_hi.hls.SymbolJumpHL,
        range["start"].line,
        range["start"].character,
        range["end"].character
    )
    -- apply it to all the references
    if node.references ~= nil then
        for _, ref in ipairs(node.references) do
            vim.api.nvim_buf_add_highlight(
                M.last_highlighted_buffer,
                M.jump_higlight_ns,
                lib_hi.hls.SymbolJumpRefsHL,
                ref["start"].line,
                ref["start"].character,
                ref["end"].character
            )
        end
    end
end

return M


================================================
FILE: lua/litee/lib/lsp/hover.lua
================================================
local M = {}

local float_win = nil

-- close_hover_popups closes the created popup window
-- if it exists.
function M.close_hover_popup()
    if float_win ~= nil and
        vim.api.nvim_win_is_valid(float_win) then
        vim.api.nvim_win_close(float_win, true)
        float_win = nil
    end
end

-- hover_handle shows hover information for a symbol in a calltree
-- ui window.
--
-- modified from neovim runtime/lua/vim/lsp/handlers.lua
-- function conforms to client LSP handler signature.
function M.hover_handler(_, result, ctx, config)
    M.close_hover_popup()
    -- get lines from result
    config = config or {}
    config.focus_id = ctx.method
    if not (result and result.contents) then
      -- return { 'No information available' }
      return
    end
    local lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents)
    lines = vim.lsp.util.trim_empty_lines(lines)
    if vim.tbl_isempty(lines) then
      -- return { 'No information available' }
      return
    end

    -- create buffer for popup
    local buf = vim.api.nvim_create_buf(false, false)
    if buf == 0 then
        vim.api.nvim_err_writeln("details_popup: could not create details buffer")
        return
    end
    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'delete')
    vim.api.nvim_buf_set_option(buf, 'syntax',    'markdown')
    vim.api.nvim_buf_set_option(buf, 'filetype',  'markdown')

    lines = vim.lsp.util.stylize_markdown(buf, lines, {})

    local width = 20
    for _, line in ipairs(lines) do
        local line_width = vim.fn.strdisplaywidth(line)
        if line_width > width then
            width = line_width
        end
    end

    vim.api.nvim_buf_set_option(buf, 'modifiable', true)
    vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)
    vim.api.nvim_buf_set_option(buf, 'modifiable', false)
    local popup_conf = vim.lsp.util.make_floating_popup_options(
            width,
            #lines,
            {
                border= "rounded",
                focusable= false,
                zindex = 99,
            }
    )
    float_win = vim.api.nvim_open_win(buf, false, popup_conf)

  return float_win
end


return M


================================================
FILE: lua/litee/lib/lsp/init.lua
================================================
local lib_notify = require('litee.lib.notify')
local lib_tree_node = require('litee.lib.tree.node')

local M = {}

-- multi_client_request makes an LSP request to multiple clients.
--
-- the signature is the same as an individual LSP client request method
-- but takes a list of clients as the first argument.
function M.multi_client_request(clients, method, params, handler, bufnr)
    for _, client in ipairs(clients) do
        if client.supports_method(method) then
            client.request(method, params, handler, bufnr or 0)
            return client
        end
    end
end

-- gather_sybmbols_async_handler is the async handler
-- for gather_symbols_async method and incrementally
-- builds a tree of symbols from a workspace symbols
-- request.
function M.gather_symbols_async_handler(node, co)
    return function(err, result, _, _)
        if err ~= nil then
            coroutine.resume(co, nil)
            return
        end
        if result == nil then
            coroutine.resume(co, nil)
            return
        end

        local start_line, uri = "", ""
        if node.call_hierarchy_item ~= nil then
            start_line = node.call_hierarchy_item.range.start.line
            uri = node.call_hierarchy_item.uri
        elseif node.document_symbol ~= nil then
            start_line = node.document_symbol.range.start.line
            uri = node.uri
        end

        for _, res in ipairs(result) do
            if
                res.location.uri == uri and
                res.location.range.start.line ==
                start_line
            then
                coroutine.resume(co, res)
                return
            end
        end
        coroutine.resume(co, nil)
    end
end

-- gather_symbols_async will acquire a list of workspace symbols given
-- a tree of call_hierarchy items.
function M.gather_symbols_async(root, children, component_state, callback)
    local co = nil
    local all_nodes = {}
    table.insert(all_nodes, root)
    for _, child in ipairs(children) do
        table.insert(all_nodes, child)
    end
    co = coroutine.create(function()
        for i, node in ipairs(all_nodes) do
            local params = {
                query = node.name,
            }
            lib_notify.notify_popup("gathering symbols [" .. i .. "/" .. #all_nodes .. "]", "warning")
            local client = M.multi_client_request(
                component_state.active_lsp_clients,
                "workspace/symbol",
                params,
                -- handler will call resume for this co.
                M.gather_symbols_async_handler(node, co)
            )
            if client.offset_encoding ~= nil then
                node.offset_encoding = client.offset_encoding
            end
            node.symbol = coroutine.yield()
            lib_notify.close_notify_popup()
        end
        callback()
    end)
    coroutine.resume(co)
end

-- symbol_from_node attempts to extract the workspace
-- symbol the node represents.
--
-- @param clients (table) All active lsp clients
-- @param node (table) A node with a "call_hierarhcy_item"
-- field we are acquiring workspace symbols for.
-- @param bufnr (int) An window handle to the buffer
-- containing the node.
-- @returns (table) the SymbolInformation LSP structure, see:
-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#symbolInformation
function M.symbol_from_node(clients, node, bufnr)
    local params = {
        query = node.name,
    }
    for _, client in ipairs(clients) do
        if not client.supports_method("workspace/symbol") then
            goto continue
        end
        -- not all LSPs are optimized, specially ones in early development, set
        -- this timeout high.
        local out = client.request_sync("workspace/symbol", params, 5000, bufnr)
        if out == nil then
            goto continue
        end
        if out.err ~= nil or (out.result == nil or #out.result <= 0) then
            goto continue
        end
        for _, res in ipairs(out.result) do
            if
                res.uri == node.uri and
                res.location.range.start.line ==
                node.call_hierarchy_item.range.start.line
            then
                return res
            end
        end
        ::continue::
    end
    return nil
end

-- conv_symbolinfo_to_docsymbol will convert a SymbolInformation
-- model to a DocumentSymbol mode.
--
-- this is handy when working with documentSymbol requests and
-- users do not want to handle two data models in their code.
--
-- @param symbolinfo (table) A SymbolInformation structure as
-- defined by the LSP specification.
-- @returns (table) A DocumentSymbol structure as defined by
-- the LSP specification.
function M.conv_symbolinfo_to_docsymbol(symbolinfo)
    local document_symbol = {}

    -- these are mandatory fields per the LSP spec,
    -- return nil if they arent there.
    if
        symbolinfo.name == nil or
        symbolinfo.kind == nil or
        symbolinfo.location == nil or
        symbolinfo.location.range == nil
    then
        return nil
    end

    document_symbol.name    = symbolinfo.name
    document_symbol.kind    = symbolinfo.kind
    document_symbol.range   = symbolinfo.location.range
    document_symbol.children = {}
    document_symbol.details = ""
    document_symbol.tags = {}
    document_symbol.deprecated = false
    document_symbol.selectionRange = symbolinfo.location.range
    return document_symbol
end

return M


================================================
FILE: lua/litee/lib/lsp/wrappers.lua
================================================
local lib_notify = require('litee.lib.notify')
local M = {}

function M.buf_document_symbol()
    lib_notify.notify_popup_with_timeout("Creating document outline...", 7500, "info")
    vim.lsp.buf.document_symbol()
end

function M.buf_incoming_calls()
    lib_notify.notify_popup_with_timeout("Creating incoming calls outline...", 7500, "info")
    vim.lsp.buf.incoming_calls()
end

function M.buf_outgoing_calls()
    lib_notify.notify_popup_with_timeout("Creating outgoing calls outline...", 7500, "info")
    vim.lsp.buf.outgoing_calls()
end

return M


================================================
FILE: lua/litee/lib/navi/init.lua
================================================
local M = {}

-- next moves the cursor in the window of the provided
-- component_state forward
--
-- @param component_state (table) A state table as defined
-- in lib/state.
-- @param pre_cb function() A callback which fires just before
-- the cursor move.
-- @param post_cb function() A callback which fires just after
-- the cursor move.
function M.next(component_state, pre_cb, post_cb)
    if component_state.win == nil
        or not vim.api.nvim_win_is_valid(component_state.win) then
        return
    end
    local cur_cursor = vim.api.nvim_win_get_cursor(component_state.win)
    local lines_nr = vim.api.nvim_buf_line_count(component_state.buf)
    if cur_cursor[1] + 1 > lines_nr then
        return
    end
    cur_cursor[1] = cur_cursor[1] + 1
    if pre_cb ~= nil then pre_cb() end
    vim.api.nvim_win_set_cursor(component_state.win, cur_cursor)
    if post_cb ~= nil then pre_cb() end
end

-- next moves the cursor in the window of the provided
-- component_state backwards
--
-- @param component_state (table) A state table as defined
-- in lib/state.
-- @param pre_cb function() A callback which fires just before
-- the cursor move.
-- @param post_cb function() A callback which fires just after
-- the cursor move.
function M.previous(component_state, pre_cb, post_cb)
    if component_state.win == nil
        or not vim.api.nvim_win_is_valid(component_state.win) then
        return
    end
    local cur_cursor = vim.api.nvim_win_get_cursor(component_state.win)
    if cur_cursor[1] - 1 < 1 then
        return
    end
    cur_cursor[1] = cur_cursor[1] - 1
    if pre_cb ~= nil then pre_cb() end
    vim.api.nvim_win_set_cursor(component_state.win, cur_cursor)
    if post_cb ~= nil then pre_cb() end
end

return M


================================================
FILE: lua/litee/lib/notify/init.lua
================================================
local notify_config = require('litee.lib.config').config["notify"]
local M = {}

local float_wins = {}

function M.close_notify_popup()
    if not notify_config.enabled then
        return
    end
    if float_wins == nil then
        return
    end
    for _, float_win in ipairs(float_wins) do
        if vim.api.nvim_win_is_valid(float_win) then
            vim.api.nvim_win_close(float_win, true)
        end
    end
    float_wins = nil
end

function M.notify_popup_with_timeout(text, ms, sev)
    if not notify_config.enabled then
        return
    end
    M.notify_popup(text, sev)
    local timer = vim.loop.new_timer()
    timer:start(ms, 0, vim.schedule_wrap(
        M.close_notify_popup
    ))
end

function M.notify_popup(text, sev)
    if not notify_config.enabled then
        return
    end

    if float_wins == nil then
        float_wins = {}
    end

    local buf = vim.api.nvim_create_buf(false, true)
    if buf == 0 then
        vim.api.nvim_err_writeln("details_popup: could not create details buffer")
        return
    end
    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'delete')
    vim.api.nvim_buf_set_option(buf, 'syntax', 'yaml')

    local lines = {text}
    local width = 20
    local line_width = vim.fn.strdisplaywidth(text)
    if line_width > width then
        width = line_width
    end

    vim.api.nvim_buf_set_option(buf, 'modifiable', true)
    vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)
    vim.api.nvim_buf_set_option(buf, 'modifiable', false)
    local popup_conf = {
        relative = "editor",
        anchor = "SE",
        width = width,
        height = 1,
        focusable = false,
        zindex = 99,
        style = "minimal",
        border = "rounded",
        row = 0,
        col = vim.opt.columns:get(),
    }
    local float_win = vim.api.nvim_open_win(buf, false, popup_conf)
    table.insert(float_wins, float_win)
    if sev == "error" then
        vim.api.nvim_win_set_option(float_win, 'winhl', "Normal:Error")
    elseif sev == "warning" then
        vim.api.nvim_win_set_option(float_win, 'winhl', "Normal:WarningMsg")
    else
        vim.api.nvim_win_set_option(float_win, 'winhl', "Normal:NormalFloat")
    end
end

return M


================================================
FILE: lua/litee/lib/panel/autocmds.lua
================================================
local lib_state = require('litee.lib.state')
local lib_panel = require('litee.lib.panel')

local M = {}

function M.on_resize()
    local cur_win = vim.api.nvim_get_current_win()
    local cur_tab = vim.api.nvim_get_current_tabpage()
    local state = lib_state.get_state(cur_tab)
    if state == nil then
        return
    end
    local is_open = lib_panel.is_panel_open(state)
    if is_open then
        lib_panel.toggle_panel(state, false, true)
        vim.api.nvim_set_current_win(cur_win)
    end
end

return M


================================================
FILE: lua/litee/lib/panel/init.lua
================================================
local lib_state = require('litee.lib.state')
local config = require('litee.lib.config').config
local lib_notify = require('litee.lib.notify')
local lib_util = require('litee.lib.util')
local lib_util_win = require('litee.lib.util.window')

local M = {}

-- components maps a unique component map
-- with a set of callbacks (see M.register_component)
--
-- the order in which components exist in this map
-- determines the component's order in the panel.
local components = {}

-- register_component adds a component to
-- the panel.
--
-- the panel's layout is determined by the
-- order in which components are registered.
--
-- registering a component *must* include a "pre_window_create"
-- callback and can optionally provide a "post_window_create"
-- callback.
--
-- @param component (string) Unique name for a component,
-- subsequent calls for a unique component will over write
-- previous
-- @param pre_window_create (function(state)) A callback which must
-- prepare the provided state object, as defined by lib/state.lua
-- with a valid buffer. The callback is free to perform any other
-- tasks such as writing to the buffer if desired. The buffer
-- ID should be stored in the component's "buf" field in state
-- and will be displayed in the appropriate panel's window on
-- toggle. This callback can return false when the window should
-- not be opened in the panel and true to indicate it should.
-- @param post_window_create (function(state)) A callback which can customize
-- the component window further after being displayed in the panel. Useful for
-- setting up component-specific window options and winhl configurations.
-- The state[component].win field will be populated with the window id of the
-- panel window for further configuration.
function M.register_component(component, pre_window_create, post_window_create)
    components[component] = {
        pre = pre_window_create,
        post = post_window_create
    }
end

function M.is_panel_open(state)
    local component_open = false
    for component, _ in pairs(components) do
        if
            state[component] ~= nil
            and state[component].win ~= nil
            and vim.api.nvim_win_is_valid(state[component].win)
        then
            component_open = true
        end
    end
    return component_open
end

-- toggle_panel will toggle the panel open and
-- close in the common case. Arguments can be
-- used to alter how the toggle takes place.
--
-- @param state (table) The full state table as defined
-- in lib/state.lua
-- @param keep_open (bool) If the panel is currently open
-- perform a no-op, useful when the caller only wants to
-- confirm the panel is present.
-- @param cycle (bool) Close and open the panel in succession,
-- useful when resizing events occur to snap the panel back
-- into the appropriate size.
function M.toggle_panel(state, keep_open, cycle, close)
    local cur_win = vim.api.nvim_get_current_win()
    -- if state is nil then try to grab it from current tab.
    if state == nil then
        local cur_tab = vim.api.nvim_get_current_tabpage()
        state = lib_state.get_state(cur_tab)
        if state == nil then
            lib_notify.notify_popup_with_timeout("Must open a litee component before toggling the panel.", 1750, "error")
            return
        end
    end
    local component_open = false
    local component_cursors = {}
    for component, _ in pairs(components) do
        if
            state[component] ~= nil
            and state[component].win ~= nil
            and vim.api.nvim_win_is_valid(state[component].win)
        then
            component_open = true
            component_cursors[component] = vim.api.nvim_win_get_cursor(state[component].win)
        end
    end

    -- components are open, close them, recording its dimensions
    -- for proper restore.
    if
        not keep_open or
        cycle or
        close
    then
        if component_open then
            for component, _ in pairs(components) do
                if
                    state[component] ~= nil
                    and state[component].win ~= nil
                    and vim.api.nvim_win_is_valid(state[component].win)
                then
                    state[component].win_dimensions = {
                        height = vim.api.nvim_win_get_height(state[component].win),
                        width = vim.api.nvim_win_get_width(state[component].win)
                    }
                    vim.api.nvim_win_close(state[component].win, true)
                end
            end
            if cycle then
                M.toggle_panel(state, false, false)
            end
            return
        end
    end

    for component, callbacks in pairs(components) do
        if state[component] ~= nil then
            if callbacks.pre(state) then
                M._open_window(component, state)
                -- restore cursor positions if possible.
                if component_cursors[component] ~= nil then
                    lib_util.safe_cursor_reset(
                        state[component].win,
                        component_cursors[component]
                    )
                end
            end
        end
    end
    vim.api.nvim_set_current_win(cur_win)
end

-- Similar to toggle_panel but retrieves state from
-- Neovim's current context.
function M.toggle_panel_ctx(keep_open, cycle)
    local state = lib_state.get_state_ctx()
    if state == nil then
        return
    end
    M.toggle_panel(state, keep_open, cycle)
end

-- realize_current_and_desired will determine the current and desired layouts
-- given a requested window type to open.
--
-- @param check_component (string) The identifier of a registered component
-- which is checked against the current layout.
-- @param desired_compoent The identifier of a registered component which is
-- the desired component to add/display in the panel.
-- @param current_layout (list of int) A list of window ids currently comprising
-- any open panel components.
-- @param desired_layout (list of string) A list of panel components desired to be
-- displayed.
-- @param state (table) A table of state as defined by lib/state.lua
--
-- @returns continue (bool) A bool which informs the caller to stop processing
-- the declarative evaluation of the panel layout. This occurs if the desired
-- component is already being displayed.
local function realize_current_and_desired(check_component, desired_component, current_layout, desired_layout, state)
    local current_tabpage = vim.api.nvim_win_get_tabpage(
        vim.api.nvim_get_current_win()
    )

    -- check if the desired window exists.
    if
        state[check_component] == nil or
        state[check_component].win == nil or
        (not vim.api.nvim_win_is_valid(state[check_component].win))
    then
        if check_component == desired_component then
            -- checked window is invalid, its also the desired window to open
            -- add it to desired layout.
            table.insert(desired_layout, desired_component)
        end
        return true
    end
    local win = state[check_component].win

    local win_tabpage = vim.api.nvim_win_get_tabpage(win)
    -- desired window type is already open on current tabpage, noop
    if check_component == desired_component and current_tabpage == win_tabpage then
        return false
    end
    -- the checked window type is open and on the current tab, unconditionally add it to
    -- desired_layout to preserve it existence.
    if current_tabpage == win_tabpage then
        table.insert(current_layout, win)
        table.insert(desired_layout, check_component)
    -- the window type we are checking is also the desired window type, but its
    -- opened in another tab, close it and add desired window type to desired layout.
    -- it will be opened on the current tab.
    elseif check_component == desired_component then
        vim.api.nvim_win_close(win, true)
        table.insert(desired_layout, desired_component)
    end
    return true
end

-- open_window will first compute the current UI layout
-- then compute the desired layout and finally call
-- _setup_window with both.
--
-- @param desired_component (string) The registered component
-- which should be opened in the panel.
--
-- @param state (table) The state table as defined by
-- lib/state.lua
function M._open_window(desired_component, state)
    -- holds open window handles we'll reuse
    local current_layout = {}
    -- holds the window types to ensure present in the ui
    local desired_layout = {}

    for check_component, _ in pairs(components) do
        if not realize_current_and_desired(check_component, desired_component, current_layout, desired_layout, state) then
            return
        end
    end

    M._setup_window(current_layout, desired_layout, state)
end

-- open_to opens the panel and moves the cursor to the requested
-- component.
--
-- if open_to is called when nvim is focused inside
-- the component the focus will be switched back to the window the ui
-- was invoked from.
--
-- @param component (string) The component to open to.
-- @param state (table) The state table as defined by
-- lib/state.lua
-- @return opened (bool) Whether the panel has been open.
function M.open_to(component, state)
    if state[component] == nil then
        -- notify.notify_popup_with_timeout("Cannot toggle panel until ..", 1750, "error")
        return false
    end
    local current_win = vim.api.nvim_get_current_win()
    if  current_win == state[component].win then
        vim.api.nvim_set_current_win(state[component].invoking_win)
        return
    end
    if
        state[component].win ~= nil
        and vim.api.nvim_win_is_valid(state[component].win)
    then
        vim.api.nvim_set_current_win(state[component].win)
        return
    end
    M.toggle_panel(state, true, false)
    vim.api.nvim_set_current_win(state[component].win)
end

M.popout_panel_state = nil

function M.close_current_popout()
    if M.popout_panel_state == nil then
        return
    end
    if vim.api.nvim_win_is_valid(M.popout_panel_state.float_win) then
        vim.api.nvim_win_close(M.popout_panel_state.float_win, true)
        -- if panel was closed when popout panel was created, close it again,
        -- otherwise open it again.
        if M.popout_panel_state.panel_open then
            -- issue a cycle here to reset any odd spacing from removing the window
            -- from the panel.
            M.toggle_panel(M.popout_panel_state.litee_state, false, true, false)
        end
    end
    M.popout_panel_state = nil
end

-- popout_to will pop the requested component
-- out of the panel to a popup on the bottom right
-- hand of the editor and focus the popup window.
--
-- if the panel is open when a call to "popout_to" is made,
-- when the popup is closed via "close_current_popout()",
-- or a jump is made with lib/jump functions,
-- then the window will be popped back into the panel.
--
-- if the panel was closed when a call to "popup_to" was made
-- this is remembered, and the panel will remain closed after
-- "close_current_popup()" is called or a jump is made with
-- lib/jump functions.
--
-- @param component (string) The registered component name
-- to create the popout for.
-- @param state (table) The current global state as defined
-- in lib/state
-- @param before_focus A callback ran just before switching
-- focus to the popout floating win. This callback is ran
-- in the original win when the call to popout_to was made.
-- @param after_focus Same as "before_focus" but runs inside
-- the newly created popout floating win.
function M.popout_to(component, state, before_focus, after_focus)
    if
        state == nil
        or state[component] == nil
        or components[component] == nil
    then
        return
    end

    -- close any popup which maybe open.
    M.close_current_popout()

    -- reset the popout panel state
    M.popout_panel_state = {}

    -- check panel open state so we can restore it correctly
    -- on close_current_popout()
    M.popout_panel_state.panel_open = M.is_panel_open(state)

    local popup_conf = {
        relative = "editor",
        anchor = "NW",
        width = math.floor(vim.opt.columns:get()/2),
        height = math.floor(vim.opt.lines:get()/2),
        focusable = true,
        zindex = 98,
        border = "rounded",
        row = math.floor(vim.opt.lines:get() - (vim.opt.cmdheight:get() + 1)/2),
        col = math.floor(vim.opt.columns:get()/2),
    }

    if  M.popout_panel_state.panel_open
        and state[component].win ~= nil
        and vim.api.nvim_win_is_valid(state[component].win)
    then
        -- if panel is open and win is valid make it a float.
        vim.api.nvim_win_set_config(state[component].win, popup_conf)
        M.popout_panel_state.float_win = state[component].win
        M.popout_panel_state.litee_state = state
    else
        -- if the panel is closed or win is not valid
        -- manually create the floating window.
        components[component].pre(state)
        M.popout_panel_state.float_win = vim.api.nvim_open_win(state[component].buf, false, popup_conf)
        state[component].win = M.popout_panel_state.float_win
        M._set_win_opts(M.popout_panel_state.float_win)
        M.popout_panel_state.litee_state = state
        vim.api.nvim_win_set_buf(M.popout_panel_state.float_win, state[component].buf)
    end

    -- run callback before focusing the callback window
    if before_focus ~= nil then
        before_focus(true)
    end

    -- set focus into float
    vim.api.nvim_set_current_win(M.popout_panel_state.float_win)

    -- if we created a floating win, we need to run post callbacks
    -- when inside of it.
    components[component].post(state)

    -- run callback after focusing the callback window
    if after_focus ~= nil then
        after_focus()
    end
end

-- setup_window evaluates the current layout and the desired layout
-- and opens the necessary windows to obtain the desired layout.
--
-- @param current_layout (list of int) A list of win handles comprising
-- the currently opened panel windows. If present, they will be reused
-- to realize the desired_layout.
-- @param desired_layout (list of string) A list of components desired
-- to be opened and present in the panel.
-- @param state (table) The state table as defined by
-- lib/state.lua
function M._setup_window(current_layout, desired_layout, state)
    for i, component in ipairs(desired_layout) do
        local buffer_to_set = nil
        local dimensions_to_set = nil

        buffer_to_set = state[component].buf
        if state[component].win_dimensions ~= nil then
            dimensions_to_set = state[component].win_dimensions
        end

        -- we can reuse the current layout windows
        if i <= #current_layout then
            vim.api.nvim_win_set_buf(current_layout[i], buffer_to_set)
            state[component].win = current_layout[i]
            vim.api.nvim_set_current_win(state[component].win)
            goto continue
        end

        -- we are out of open windows, so we need to create some

        if #current_layout == 0 then
            -- there is no current layout, so just do a botright or equivalent
            if config["panel"].orientation == "left" then
                vim.cmd("topleft vsplit")
                vim.cmd("vertical resize " ..
                            config["panel"].panel_size)
            elseif config["panel"].orientation == "right" then
                vim.cmd("botright vsplit")
                vim.cmd("vertical resize " ..
                            config["panel"].panel_size)
            elseif config["panel"].orientation == "top" then
                vim.cmd("topleft split")
                vim.cmd("resize " ..
                            config["panel"].panel_size)
            elseif config["panel"].orientation == "bottom" then
                vim.cmd("botright split")
                vim.cmd("resize " ..
                            config["panel"].panel_size)
            end
            goto set
        end

        -- cursor currently in a reused window, split according to layout config
        if config["panel"].orientation == "left" then
            vim.cmd("below split")
        elseif config["panel"].orientation == "right" then
            vim.cmd("below split")
        elseif config["panel"].orientation == "top" then
            vim.cmd("vsplit")
        elseif config["panel"].orientation == "bottom" then
            vim.cmd("vsplit")
        end

        ::set::
        cur_win = vim.api.nvim_get_current_win()
        state[component].win = cur_win
        vim.api.nvim_win_set_buf(state[component].win, buffer_to_set)
        M._set_win_opts(state[component].win)
        if
            dimensions_to_set ~= nil and
            dimensions_to_set.width ~= nil and
            dimensions_to_set.height ~= nil
        then
            if (config["panel"].orientation == "left" or config["panel"].orientation == "right") then
                vim.api.nvim_win_set_width(cur_win, dimensions_to_set.width)
            else
                vim.api.nvim_win_set_height(cur_win, dimensions_to_set.height)
            end
        else
            dimensions_to_set = {}
            dimensions_to_set.height = vim.api.nvim_win_get_height(cur_win)
            dimensions_to_set.wdith  = vim.api.nvim_win_get_width(cur_win)
            state[component].dimensions = dimensions_to_set
        end

        ::continue::
        if components[component].post ~= nil then
            components[component].post(state)
        end
    end
end

-- _set_win_opts sets the manditory window options for a
-- panel window.
-- @param win (int) Window ID of panel window
function M._set_win_opts(win)
    vim.api.nvim_win_set_option(win, 'number', false)
    vim.api.nvim_win_set_option(win, 'cursorline', true)
    vim.api.nvim_win_set_option(win, 'relativenumber', false)
    vim.api.nvim_win_set_option(win, 'signcolumn', 'no')
    vim.api.nvim_win_set_option(win, 'wrap', false)
    vim.api.nvim_win_set_option(win, 'winfixwidth', true)
    vim.api.nvim_win_set_option(win, 'winfixheight', true)
    vim.api.nvim_win_set_option(win, 'winhighlight', 'Normal:NormalSB')
end

return M


================================================
FILE: lua/litee/lib/state/autocmds.lua
================================================
local lib_tree  = require('litee.lib.tree')
local lib_state = require('litee.lib.state')

local M = {}

M.on_tab_closed = function(tab)
    local state = lib_state.get_state(tab)
    if state == nil then
        return
    end
    for _, s in pairs(state) do
        if s ~= nil then
            lib_tree.remove_tree(s.tree)
        end
    end
    lib_state.put_state(tab, nil)
end

return M


================================================
FILE: lua/litee/lib/state/init.lua
================================================
local M = {}

-- registry is a per-tab-page registry for
-- state.
--
-- state defines information necessary for
-- a UI component to be used with litee-lib.
--
-- the state structure is as follows:
-- "component" = {
--     buf = 0,
--     win = 0,
--     tab = 0,
--     tree = 0,
--     win_dimensions = {0, 0},
--     invoking_win = 0,
--     active_lsp_clients = {list of lsp clients},
--     (component specific fields)...
-- }
--
-- a component using the registry should consider
-- only it's portion of the state as writable but
-- is free to pass the full state object to other
-- lib methods.
M.registry = {}

-- get_state returns the state for the given tab
-- @param tab (int) The tab ID to retrieve state for.
-- @returns state (table) The state as defined by this
-- module.
function M.get_state(tab)
    return M.registry[tab]
end

-- get_state_ctx is similiar to get_state but obtains
-- the tab ID from the current Neovim context.
function M.get_state_ctx()
    local win    = vim.api.nvim_get_current_win()
    local tab    = vim.api.nvim_win_get_tabpage(win)
    local state = M.registry[tab]
    return state
end

-- get_component_state returns the state for a
-- particular component that's utilizing lib state.
--
-- @param tab (int) The tab ID to retrieve state for.
-- @param component (string) The name of the component
-- storing its state.
function M.get_component_state(tab, component)
    local s = M.registry[tab]
    if s == nil then return nil end
    return s[component]
end

-- put_state writes a state table to the registry for
-- later retrieval.
--
-- this method overwrites all current state so use with
-- caution.
-- @param tab (int) The tab ID to associate the provided state
-- with
-- @param state (table) The state as defined by this
-- module.
-- @returns state (table) The updated state table as defined
-- by this module
function M.put_state(tab, state)
    M.registry[tab] = state
    return M.registry[tab]
end


-- put_component_state will store the component state for
-- later retrieval.
--
-- @param tab (int) The tab ID to associate the provided state
-- with
-- @param component (string) The name of the component
-- storing its state table.
-- @param state (table) The state as defined by this
-- module. This table should not include the component
-- name as a leading key.
-- @returns state (table) The updated state table as defined
-- by this module
function M.put_component_state(tab, component, state)
    local s = M.registry[tab]
    if s == nil then
        s = {}
        M.registry[tab] = s
    end
    s[component] = state
    return s
end

function M.get_active_components(tab)
    local s = M.registry[tab]
    local components = {}
    for component, _ in pairs(s) do
        table.insert(components, component)
    end
    return components
end

function M.get_type_from_buf(tab, buf)
    local state = M.registry[tab]
    if state == nil then
        return nil
    end
    for component, s in pairs(state) do
        if buf == s.buf then
            return component
        end
    end
    return nil
end

M.get_tree_from_buf = function(tab, buf)
    local state = M.registry[tab]
    if state == nil then
        return nil
    end
    local type = M.get_type_from_buf(tab, buf)
    if type == nil then
        return nil
    end
    return state[type].tree
end

return M


================================================
FILE: lua/litee/lib/term/init.lua
================================================
local lib_panel = require('litee.lib.panel')
local lib_state = require('litee.lib.state')
local lib_util_buf = require('litee.lib.util.buffer')
local config = require('litee.lib.config').config["term"]

local M = {}

local opts = {noremap = true, silent=true}
local function terminal_buf_setup(buf)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>v", "<cmd>lua require('configs.terminal').terminal_vsplit()<cr>", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>n", "<C-\\><C-n>", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>h", "<C-\\><C-n><C-w>h", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>j", "<C-\\><C-n><C-w>j", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>k", "<C-\\><C-n><C-w>k", opts)
    vim.api.nvim_buf_set_keymap(buf, 't', "<C-w>l", "<C-\\><C-n><C-w>l", opts)
    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'hide')
	if config.map_resize_keys then
           lib_util_buf.map_resize_keys(config.position, buf, opts)
    end
end
local function terminal_win_setup(win)
    vim.api.nvim_win_set_option(win, 'winfixheight', true)
end

-- terminal opens a native Neovim terminal instance that
-- is aware of the litee.panel layout.
--
-- the terminal will not truncate the panel if it is open
-- on the left or right position.
--
-- the terminal can be opened at the top of bottom of the
-- editor, but not left or right and this is configured
-- via the 'litee.lib.config.term["position"]' stanza.
--
-- the terminal has a fixed height so a call to <C-w>=
-- does not effect the height and only evenly spaces
-- any vsplit terminals in the pane.
--
-- the $SHELL environment variable must be set correctly
-- to open the appropriate shell.
function M.terminal()
    local shell = vim.fn.getenv('SHELL')
    if shell == nil or shell == "" then
        return
    end
    local buf = vim.api.nvim_create_buf(false, false)
    if buf == 0 then
        vim.api.nvim_err_writeln("failed to create terminal buffer")
        return
    end

    terminal_buf_setup(buf)

    if config.position == "top" then
        vim.cmd('topleft split')
    else
        vim.cmd('botright split')
    end
    vim.cmd("resize " .. config.term_size)
    terminal_win_setup(vim.api.nvim_get_current_win())
    local cur_win = vim.api.nvim_get_current_win()
    local cur_tab = vim.api.nvim_get_current_tabpage()
    local state = lib_state.get_state(cur_tab)
    vim.api.nvim_win_set_buf(cur_win, buf)
    vim.fn.termopen(shell)
    if state ~= nil then
        if lib_panel.is_panel_open(state) then
            lib_panel.toggle_panel_ctx(true, true)
        end
    end
    vim.api.nvim_set_current_win(cur_win)
end

function M.terminal_vsplit()
    local shell = vim.fn.getenv('SHELL')
    if shell == nil or shell == "" then
        return
    end
    local buf = vim.api.nvim_create_buf(false, false)
    if buf == 0 then
        vim.api.nvim_err_writeln("failed to create terminal buffer")
        return
    end
    vim.cmd('vsplit')
    local cur_win = vim.api.nvim_get_current_win()
    terminal_win_setup(cur_win)
    vim.api.nvim_win_set_buf(cur_win, buf)
    vim.fn.termopen(shell)
    terminal_buf_setup(buf)
end

function M.list_terminals()
    local terms = {}
    for _, b in ipairs(vim.api.nvim_list_bufs()) do
        local buf_name = vim.api.nvim_buf_get_name(b)
        if vim.fn.match(buf_name, "term://") == 0 then
            table.insert(terms, {name = buf_name, buf = b})
        end
    end
    if #terms == 0 then
        return
    end
    vim.ui.select(
        terms,
        {
            prompt = "select a terminal to display",
            format_item = function(item)
                return item["name"] .. " " .. item["buf"]
            end
        },
        function (choice)
            -- first see if there's a window that's opened with this term
            for _, w in ipairs(vim.api.nvim_list_wins()) do
                if vim.api.nvim_win_get_buf(w) == choice["buf"] then
                    vim.api.nvim_set_current_win(w)
                    return
                end
            end

            if config.position == "top" then
                vim.cmd('topleft split')
            else
                vim.cmd('botright split')
            end
            vim.cmd("resize " .. config.term_size)
            local cur_win = vim.api.nvim_get_current_win()
            local cur_tab = vim.api.nvim_get_current_tabpage()
            local state = lib_state.get_state(cur_tab)
            vim.api.nvim_win_set_buf(cur_win, choice["buf"])
            if state ~= nil then
                if lib_panel.is_panel_open(state) then
                    lib_panel.toggle_panel_ctx(true, true)
                end
            end
            vim.api.nvim_set_current_win(cur_win)
        end
    )
end

return M


================================================
FILE: lua/litee/lib/tree/init.lua
================================================
local lib_marshal = require('litee.lib.tree.marshal')

local M = {}

-- registry keeps a mapping between tree handles
-- and a tree table.
--
-- the registry and tree table stricture is defined
-- below:
-- {
--   1: {root = {}, depth_table = {}, kind = "", source_line_map = nil, buf_line_map = nil}
-- }
-- 1 is the the associated handle returned by new_tree
-- root is the root node of the tree
--
-- depth_table is the depth table associated with the tree
--
-- kind is the kind of tree and will typically be a component's
-- name as defined in lib/state.lua
local registry = {}

-- new_tree registers an empty tree and returns
-- the handle to the caller.
--
-- @param kind (string) A string representing, at
-- a high level, the kind of tree being created.
-- @returns tree_handle (int) A handle representing
-- the created tree.
function M.new_tree(kind)
    local handle = #registry+1
    registry[handle] = {root = {}, depth_table = {}, kind = kind}
    return handle
end

-- get_tree takes a call handle and returns a table
-- representing our tree components.
--
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
-- @returns tree (table) A tree table as defined
-- in this module, see "registry" comments.
function M.get_tree(handle)
    local t = registry[handle]

    -- attach marshaler info to tree if it exists.
    if t ~= nil then
        t.source_line_map = lib_marshal.source_line_map[handle]
        t.buf_line_map = lib_marshal.buf_line_map[handle]
    end

    return registry[handle]
end

-- remove_tree takes a call handle and removes
-- the associated tree from memory.
--
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
function M.remove_tree(handle)
    if handle == nil then
        return
    end
    if registry[handle] == nil then
        return
    end
    registry[handle] = nil
end

-- search_dpt will search the dpt at the given
-- depth for the given key.
--
-- @param dpt (table) A depth table retrieved
-- from a previous call to get_tree.
-- @param depth (int) The depth at which to search
-- for the key
-- @param key (string) The node's key to search
-- for
-- @returns node (table) If found, a node table
-- as defined in lib/tree/node.lua. Nil if search
-- fails.
function M.search_dpt(dpt, depth, key)
    local nodes = dpt[depth]
    if nodes == nil then
        return nil
    end
    for _, node in ipairs(nodes) do
        if node.key == key then
            return node
        end
    end
    return nil
end

-- recursive_dpt_compute traverses the tree
-- and flattens it into out depth_table
--
-- @param node (table) A node table
-- as defined in lib/tree/node.lua
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
local function _recursive_dpt_compute(handle, node)
    local depth = node.depth
    if registry[handle].depth_table[depth] == nil then
        registry[handle].depth_table[depth] = {}
    end
    table.insert(registry[handle].depth_table[depth], node)
    -- recurse
    for _, child in ipairs(node.children) do
        _recursive_dpt_compute(handle, child)
    end
end

-- _refresh_dpt dumps the current depth_table
-- and writes a new one.
--
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
local function _refresh_dpt(handle)
    registry[handle].depth_table = {}
    _recursive_dpt_compute(handle, registry[handle].root)
end

-- add_node will add a node to the tree pointed to by the
-- provided tree handle.
--
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
-- @param parent (table) The parent node table of the subtree being
-- added. the parent's "depth" field is significant. setting it to
-- 0 will throw away the current root and create a new tree.
-- See usages of this function to understand how depth can be safely
-- set.
-- @param children (table) The children of the parent.
-- the child's depth field has no significant and can be computed
-- from the parents (unless external is used, see below).
-- @param external (bool) If true an entire tree has been built externally
-- and the root will be added to the tree without any modifications.
-- the children param has no significance in this scenario.
-- note: when using external the calling code must set the all parent
-- and children depth fields correctly.
function M.add_node(handle, parent, children, external)
    if registry[handle] == nil then
        return
    end
    -- external nodes are roots of trees built externally
    -- if this is true set the tree's root to the incoming parent
    -- and immediately return
    if external then
        registry[handle].root = parent
        _refresh_dpt(handle)
        return
    end

    -- if depth is 0 we are creating a new call tree.
    if parent.depth == 0 then
        registry[handle].root = parent
        registry[handle].expanded = true
        registry[handle].depth_table = {}
        registry[handle].depth_table[0] = {}
        table.insert(registry[handle].depth_table[0], registry[handle].root)
    end

    -- if parent's depth doesn't exist we can't
    -- continue.
    if registry[handle].depth_table[parent.depth] == nil then
        -- this is an error
        return
    end

    -- lookup parent node in depth tree (faster then tree diving.)
    local pNode = nil
    for _, node in pairs(registry[handle].depth_table[parent.depth]) do
        if node.key == parent.key then
            pNode = node
            break
        end
    end
    if pNode == nil then
        return
    end

    -- ditch the old child array, we are refreshing the children
    pNode.children = {}

    local child_depth = parent.depth + 1
    for _, child  in ipairs(children) do
        child.depth = child_depth
        table.insert(pNode.children, child)
    end
    _refresh_dpt(handle)
end

-- remove subtree will remove the subtree of the
-- provided node, leaving the root node present.
--
-- @param node (table) A node table
-- as defined in lib/tree/node.lua. This node must
-- be the root of the subtree being removed.
-- @param root (bool) Should be "true", indicator that
-- recursion is at the root node.
function M.remove_subtree(tree, node, root)
    -- recurse to leafs
    for _, child in ipairs(node.children) do
        M.remove_subtree(tree, child, false)
    end
    if not root then
        -- remove yourself from the depth table
        local dt = registry[tree].depth_table[node.depth]
        local nw_dt = {}
        for _, dt_node in ipairs(dt) do
            if dt_node.key ~= node.key then
                table.insert(nw_dt, dt_node)
            end
        end
        registry[tree].depth_table[node.depth] = nw_dt
    end
    if root then
        -- remove your children
        node.children = {}
    end
end

-- collapse subtree will recursively collapse the
-- subtree starting at root and inclusive to root.
--
-- this function does not modify the tree structure
-- like "remove_subtree" but rather sets all nodes in the
-- subtree to expanded = false. on next marshal of the
-- tree the nodes will be collapsed.
--
-- @param node (table) A node table
-- as defined in lib/tree/node.lua, this node must be
-- the root of the subtree to be collapsed.
function M.collapse_subtree(root)
    root.expanded = false
    for _, child in ipairs(root.children) do
        M.collapse_subtree(child)
    end
end

-- reparent_node will make the provided node
-- the root of the provided tree, discarding
-- any ancestors above it in the process.
--
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
--
-- @param depth (int) The depth at which to search
-- for the key
-- @param node (table) A node table
-- as defined in lib/tree/node.lua, this node must be
-- the desired new root of the tree.
function M.reparent_node(handle, depth, node)
    -- we are the new root, dump the current root_node and
    -- set yourself
    if depth == 0 then
        registry[handle].root = node
        registry[handle].root.depth = 0
    end
    -- recurse to leafs
    for _, child in ipairs(node.children) do
        M.reparent_node(handle, depth+1, child)
        -- recursion done, update your depth
        child.depth = depth+1
    end
    if depth == 0 then
        -- we are the root node, refresh depth_table with
        -- new tree.
        _refresh_dpt(handle)
    end
end

-- dump_tree will dump the tree data structure to a
-- buffer for debugging.
--
-- @param node (table) A node table
-- as defined in lib/tree/node.lua, this node can be
-- a root or a child depending on where in the tree
-- you'd like to dump.
function M.dump_tree(node)
    local buf = vim.api.nvim_create_buf(true, false)
    vim.api.nvim_buf_set_name(buf, "calltree-dump")
    vim.cmd("botright split")
    local win = vim.api.nvim_get_current_win()
    local lines = vim.fn.split(vim.inspect(node), "\n")
    vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
    vim.api.nvim_win_set_buf(win, buf)
    vim.api.nvim_set_current_win(win)
end

-- write_tree recursively marshals all nodes from the provided root
-- down, into UI lines and writes those lines to the provided buffer.
--
-- @param buf  (int) The buffer handle to write the marshalled tree to
-- @param tree (int) The tree handle to marshal into the provided buffer
-- @param marshal_func (function(node)) A function
-- when given a node returns the following strings
    -- name: the display name for the node
    -- detail: details to display about the node
    -- icon: any icon associated with the node
function M.write_tree(buf, tree, marshal_func, no_guide_leaf)
    local root = registry[tree].root
    if root == nil then
        return
    end
    lib_marshal._marshal_tree(buf, {}, root, tree, {}, marshal_func, no_guide_leaf)
    return buf
end

-- same as `write_tree` but forces `no_guide_leaf` to be true
-- on each call.
--
-- useful for clients of the lib which always choose this option.
function M.write_tree_no_guide_leaf(buf, tree, marshal_func)
    M.write_tree(buf, tree, marshal_func, true)
end

-- marshal_line takes a UI buffer line and
-- marshals it into a tree.Node.
--
-- @param linenr (table) A buffer line as returned by
-- vim.api.nvim_win_get_cursor()
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
--
-- @param node (table) A node table
-- as defined in lib/tree/node.lua, nil if
-- marshal failed.
function M.marshal_line(linenr, handle)
    return lib_marshal.marshal_line(linenr, handle)
end

function M.flatten_depth_table(dtp)
    local nodes = {}
    for _, depth in pairs(dtp) do
        for _, node in ipairs(depth) do
            table.insert(nodes, node)
        end
    end
    return nodes
end

return M


================================================
FILE: lua/litee/lib/tree/marshal/init.lua
================================================
local lib_util = require('litee.lib.util')
local lib_hi    = require('litee.lib.highlights')
local lib_tree_config = require('litee.lib.config').config["tree"]
local icon_set = require('litee.lib').icon_set

local M = {}

-- buf_line_map keeps a mapping between marshaled
-- buffer lines and the node objects for a given tree.
--
-- the structure of this table is as follows:
-- {
--   tree_handle = {
--      line_number = node,
--      ...
--   },
--   ...
-- }
M.buf_line_map = {}

-- maps source code lines to buffer lines
-- for a given tree.
--
-- currently only useful for symboltree.
--
-- the struture of this table is as follows:
-- {
--   tree_handle = {
--      source_file_line_number = {
--          uri = relative_path_to_file,
--          line = calltree_buffer_line_number
--      }
--      ...
--   }
--   ...
-- }
M.source_line_map = {}

-- marshal_node takes a node and a marshal_func and
-- produces a buffer line.
--
-- @param node (table) A node table
-- as defined in lib/tree/node.lua, this node must
-- be the node being marshalled into a line.
-- @param marshal_func (function(node)) A function
-- when given a node returns the following strings
-- name: the display name for the node
-- detail: details to display about the node
-- icon: any icon associated with the node
-- expand_guide: optional override when the marshal
-- func want to specify a specific expand guide.
-- @param no_guide_leaf (bool) If node is a leaf
-- node and this bool is true an expansion guide
-- will be ommited from the rendered line.
-- @return buffer_line (string) a string with
-- the preamble of the buffer line.
-- @return virt_text (table) A table suitable for
-- configuring virtual text containing the details
-- of the node. This virtual text will be placed EOL
-- in the buffer line.
function M.marshal_node(node, marshal_func, no_guide_leaf)
    local expand_guide = ""
    if node.expanded then
        expand_guide = icon_set["Expanded"]
    else
        expand_guide = icon_set["Collapsed"]
    end
    if no_guide_leaf
        and #node.children == 0
        and node.expanded == true
    then
        expand_guide = icon_set["Space"]
    end

    local str = ""

    local name, detail, icon, expand_guide_override = marshal_func(node)

    if expand_guide_override ~= nil then
        expand_guide = expand_guide_override
    end

    if lib_tree_config.indent_guides then
        for i=1, node.depth do
            if i == 1 then
                str = str .. icon_set["Space"]
            else
                str = str .. icon_set["IndentGuide"] .. icon_set["Space"]
            end
        end
    else
        for _=1, node.depth do
            str = str .. icon_set["Space"]
        end
    end

    if icon == nil then
        icon = " "
    end

    -- ▶ Func1
    str = str .. expand_guide .. icon_set["Space"]
    str = str .. icon .. icon_set["Space"]  .. icon_set["Space"] .. name
    -- return detail as virtual text chunk.
    return str, {{detail, lib_hi.hls.SymbolDetailHL}}
end

-- marshal_line takes a UI buffer line and
-- marshals it into a tree.Node.
--
-- @param linenr (table) A buffer line as returned by
-- vim.api.nvim_win_get_cursor()
-- @param handle (int) A tree handle ID previously
-- returned from a call to new_tree
--
-- @param node (table) A node table
-- as defined in lib/tree/node.lua, nil if
-- marshal failed.
function M.marshal_line(linenr, handle)
    if M.buf_line_map == nil then
        return nil
    end
    if M.buf_line_map[handle] == nil then
        return nil
    end
    local node = M.buf_line_map[handle][linenr[1]]
    return node
end

-- marshal_tree recursively marshals all nodes from the provided root
-- down, into UI lines.
--
-- @param buf (int) The buffer handle to write the marshalled tree to
-- @param lines (list of string) Recursive accumlator of marshaled
-- lines. Start this function with an empty table.
-- @param node (table) A node table as defined in lib/tree/node.lua,
-- this node must be the root  of the tree being marshalled into buffer lines.
-- @param virtual_text_lines (list of string) Recursive accumlator of marshaled
-- virtual text lines. Start this function with an empty table.
-- @param marshal_func (function(node)) A function
-- when given a node returns the following strings
    -- name: the display name for the node
    -- detail: details to display about the node
    -- icon: any icon associated with the node
function M._marshal_tree(buf, lines, node, tree, virtual_text_lines, marshal_func, no_guide_leaf)
    if node.depth == 0 then
        virtual_text_lines = {}
        -- create a new line mapping
        M.buf_line_map[tree] = {}
        M.source_line_map[tree] = {}
    end

    local line, virtual_text = M.marshal_node(node, marshal_func, no_guide_leaf)
    table.insert(lines, line)
    table.insert(virtual_text_lines, virtual_text)
    M.buf_line_map[tree][#lines] = node

    -- if the node has a location we can track where it
    -- exists in the source code file.
    if node.location ~= nil and not vim.tbl_isempty(node.location) then
        local start_line = node.location["range"]["start"].line
        M.source_line_map[tree][start_line+1] = {
            uri = lib_util.absolute_path_from_uri(node.location.uri),
            line = #lines
        }
    end

    -- if we are an expanded node or we are the root (always expand)
    -- recurse
    if node.expanded  or node.depth == 0 then
        for _, child in ipairs(node.children) do
            M._marshal_tree(buf, lines, child, tree, virtual_text_lines, marshal_func, no_guide_leaf)
        end
    end

    -- we are back at the root, all lines are inserted, lets write it out
    -- to the buffer
    if node.depth == 0 then
        vim.api.nvim_buf_set_option(buf, 'modifiable', true)
        vim.api.nvim_buf_set_lines(buf, 0, -1, true, {})
        vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)
        vim.api.nvim_buf_set_option(buf, 'modifiable', false)
        for i, vt in ipairs(virtual_text_lines) do
            if vt[1][1] == "" then
                goto continue
            end
            local opts = {
                virt_text = vt,
                virt_text_pos = 'eol',
                hl_mode = 'combine'
            }
            vim.api.nvim_buf_set_extmark(buf, 1, i-1, 0, opts)
            ::continue::
        end
    end
end

return M


================================================
FILE: lua/litee/lib/tree/node.lua
================================================
local M = {}

-- new_node creates a polymorphic node
-- which the caller can attach their own
-- node specific fields to.
--
-- a unique key must be generated and provided
-- along with the desired depth of the node with
-- the tree it will belong in.
--
-- see function definition for node field documentation.
-- only the requird fields are present in the constructor
-- optional fields can be added on to the node by the caller.
--
-- @param name (string) a non-unique display name
-- for the node.
-- @param key (string) a unique key used to identify
-- the node when placed into a tree.
-- @param depth (int) the node's depth in the tree, zero
-- indexed. depth 0 indicates this node is the root of
-- the tree.
-- @returns (table) A table representing a node object.
-- the caller is free to attach domain specific fields
-- that convey the node's purpose othorgonal to the usage
-- in the tree.
function M.new_node(name, key, depth)
    return {
        -- a non-unique display name for the node
        name = name,
        -- the depth of the node in the target tree
        depth = depth,
        -- a unique key used to identify the node when
        -- placed into a tree
        key = key,
        -- a list of children nodes with recursive definitions.
        children = {},
        -- a "Location" object as defined by the LSP which
        -- associates this node with a source code file and line range.
        -- see:
        -- https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#location
        location = {},
        -- a list of "Range" objects, relative to the above location object,
        -- which relate in a domain specific way to this node.
        -- see:
        -- https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#range
        references = {},
        -- whether this node is expanded in its containing
        -- tree.
        expanded = false,
        offset_encoding = "utf-8"
    }
end

return M


================================================
FILE: lua/litee/lib/util/buffer.lua
================================================
local M = {}


local original_guicursor = ""
-- hide_cursor will dynamically create the LTCursorHide hi and
-- set the guicursor option to this hi group.
--
-- the LTCursorHide hi has the same bg/fg as the CursorLine hi which
-- is used inside the LITEE.nvim windows.
--
-- this effectively hides the cursor by making it blend into the cursor
-- line.
--
-- hide : bool - if true hides the cursor if false sets the guicursor
-- option back to the value when Neovim started.
function M.hide_cursor(hide)
    if original_guicursor == "" then
        for _, section in ipairs(vim.opt.guicursor:get()) do
            original_guicursor = original_guicursor .. section .. ','
        end
    end
    if not hide then
        vim.cmd('set guicursor=' .. original_guicursor)
        return
    end
    local colors_rgb = vim.api.nvim_get_hl_by_name("CursorLine", true)
    local colors_256 = vim.api.nvim_get_hl_by_name("CursorLine", false)
    local hi = string.format("hi LTCursorHide cterm=None ctermbg=%s ctermfg=%s gui=None guibg=%s guifg=%s",
        (function() if colors_256.background ~= nil then return colors_256.background else return "None" end end)(),
        (function() if colors_256.foreground ~= nil then return colors_256.foreground else return "None" end end)(),
        (function() if colors_rgb.background ~= nil then return string.format("#%x", colors_rgb.background) else return "None" end end)(),
        (function() if colors_rgb.foreground ~= nil then return string.format("#%x", colors_rgb.foreground) else return "None" end end)()
    )
    vim.cmd(hi)
    local cursorgui = "set guicursor=n:LTCursorHide"
    vim.cmd(cursorgui)
end

-- set_scrolloff will enable a global scrolloff
-- of 999 when set is true.
--
-- when set is false the scrolloff will be set back to 0.
-- useful for keeping the contents of a litee panel centered.
function M.set_scrolloff(set)
    if set then
        vim.cmd("set scrolloff=999")
    else
        vim.cmd("set scrolloff=0")
    end
end

function M.map_resize_keys(orientation, buffer_handle, opts)
    if orientation == "top" then
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Right>", ":vert resize +5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Left>", ":vert resize -5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Up>", ":resize +5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Down>", ":resize -5<cr>", opts)
    elseif orientation == "bottom" then
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Right>", ":vert resize +5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Left>", ":vert resize -5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Down>", ":resize +5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Up>", ":resize -5<cr>", opts)
    elseif orientation == "left" then
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Up>", ":resize +5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Down>", ":resize -5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Left>", ":vert resize -5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Right>", ":vert resize +5<cr>", opts)
    elseif orientation == "right" then
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Up>", ":resize +5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Down>", ":resize -5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Left>", ":vert resize +5<cr>", opts)
        vim.api.nvim_buf_set_keymap(buffer_handle, "n", "<Right>", ":vert resize -5<cr>", opts)
    end
end

-- a convenience method which will close any popups
-- generated by the litee library (not notifications).
function M.close_all_popups()
    require('litee.lib.lsp.hover').close_hover_popup()
    require('litee.lib.details').close_details_popup()
end

return M


================================================
FILE: lua/litee/lib/util/init.lua
================================================
local M = {}

function M.absolute_path_from_uri(uri)
    local uri_path = vim.fn.substitute(uri, "file://", "", "")
    return uri_path
end

-- safe_cursor_reset will attempt to move the
-- cursor to `linenr`, if the provided `linenr`
-- would overflow the buffer the cursor will
-- safely be placed at the lowest available
-- buffer line.
function M.safe_cursor_reset(win, linenr)
    if
        win == nil
        or not vim.api.nvim_win_is_valid(win)
        or linenr == nil
    then
        return
    end
    local lc = vim.api.nvim_buf_line_count(vim.api.nvim_win_get_buf(win))
    if lc < linenr[1] then
        linenr[1] = lc
    end
    vim.api.nvim_win_set_cursor(win, linenr)
end

function M.relative_path_from_uri(uri)
    local cwd = vim.fn.getcwd()
    local uri_path = vim.fn.substitute(uri, "file://", "", "")
    local idx = vim.fn.stridx(uri_path, cwd)
    if idx == -1 then
        -- we can't resolve a relative path, just give the
        -- full path to the file.
        return uri_path, false
    end
    return vim.fn.substitute(uri_path, cwd .. "/", "", ""), true
end

function M.resolve_location(node)
    local location = nil
    if node.symbol ~= nil then
        location = node.symbol.location
    elseif node.call_hierarchy_item ~= nil then
        location = {
            uri = node.call_hierarchy_item.uri,
            range = node.call_hierarchy_item.range
        }
    elseif node.document_symbol ~= nil then
        location = {
            uri = node.uri,
            range = node.document_symbol.selectionRange
        }
    elseif node.filetree_item ~= nil then
        local range = {}
        range["start"] = { line = 0, character = 0}
        range["end"] = { line = 0, character = 0}
        location = {
            uri = "file://" .. node.filetree_item.uri,
            range = range
        }
    end
    return location
end

function M.resolve_absolute_file_path(node)
    if node.symbol ~= nil then
        local uri = node.symbol.location.uri
        return M.absolute_path_from_uri(uri)
    elseif node.call_hierarchy_item ~= nil then
        local uri = node.call_hierarchy_item.uri
        return M.absolute_path_from_uri(uri)
    elseif node.document_symbol ~= nil then
        local uri = node.uri
        return M.absolute_path_from_uri(uri)
    else
        return nil
    end
end

function M.resolve_hover_params(node)
    local params = {}
    if node.symbol ~= nil then
        params.textDocument = {
            uri = node.symbol.location.uri
        }
        params.position = {
            line = node.symbol.location.range.start.line,
            character = node.symbol.location.range.start.character
        }
    elseif node.call_hierarchy_item ~= nil then
        params.textDocument = {
            uri = node.call_hierarchy_item.uri
        }
        params.position = {
            line = node.call_hierarchy_item.range.start.line,
            character = node.call_hierarchy_item.range.start.character
        }
    elseif node.document_symbol ~= nil then
        params.textDocument = {
            uri = node.uri
        }
        params.position = {
            line = node.document_symbol.selectionRange.start.line,
            character = node.document_symbol.selectionRange.start.character
        }
    else
        return nil
    end
    return params
end

return M


================================================
FILE: lua/litee/lib/util/path.lua
================================================
local M = {}

-- safe_encode returns a string which is safe to
-- use as a filesystem name.
--
-- this is helpful when encoding filesystem paths
-- to a string that can be used as a filename.
--
-- the encoding is just a sub-set of URL encoding.
--
-- @param str (string) The string to encode.
function M.safe_encode(str)
    str, _ = string.gsub(str, '/', '%%2F')
    str, _ = string.gsub(str, ' ', '%%20')
    str, _ = string.gsub(str, ':', '%%3A')
    return str
end

-- decodes a string encoded by safe_encode.
-- see safe_encode for details.
function M.safe_decode(str)
    str, _ = string.gsub(str, '%%2F', '/')
    str, _ = string.gsub(str, '%%20', ' ')
    str, _ = string.gsub(str, '%%3A', ':')
    return str
end

function M.is_dir(path)
    if vim.fn.isdirectory(path) == 0 then
        return false
    end
    return true
end

function M.file_exists(path)
    if vim.fn.filereadable(path) == 0 then
        return false
    end
    return true
end

function M.relative_path_from_uri(uri)
    local cwd = vim.fn.getcwd()
    local uri_path = vim.fn.substitute(uri, "file://", "", "")
    local idx = vim.fn.stridx(uri_path, cwd)
    if idx == -1 then
        -- we can't resolve a relative path, just give the
        -- full path to the file.
        return uri_path, false
    end
    return vim.fn.substitute(uri_path, cwd .. "/", "", ""), true
end

-- provides the filename with no path details for
-- the provided uri.
function M.basename(uri)
    local final_sep = vim.fn.strridx(uri, "/")
    local uri_len   = vim.fn.strlen(uri)

    -- if its a dir, remove final "/"
    if final_sep+1 == uri_len then
        uri = vim.fn.strpart(uri, 0, uri_len-1)
        final_sep = vim.fn.strridx(uri, "/")
    end

    local dir = vim.fn.strpart(uri, final_sep+1, vim.fn.strlen(uri))
    return dir
end

function M.parent_dir(path)
        local base = M.basename(path)
        local diff = vim.fn.strlen(path) - (vim.fn.strlen(base)+1)
        local res = vim.fn.strpart(path, 0, diff)
        if vim.fn.strridx(path, "/") == #path-1 then
            return res
        else
            return res .. "/"
        end
end

function M.path_prefix_match(prefix, path)
    local idx = vim.fn.stridx(path, prefix)
    if idx == -1 then
        return false
    end
    return true
end

function M.swap_path_prefix(path, old_prefix, new_prefix)
    local new_path = vim.fn.substitute(path, old_prefix, new_prefix, "")
    return new_path
end

function M.strip_file_prefix(path)
    return vim.fn.substitute(path, "file://", "", "")
end

function M.add_file_prefix(path)
    vim.fn.substitute(path, "file://", "", "")
    return string.format("%s%s", "file://", path)
end

function M.strip_trailing_slash(path)
    if vim.fn.strridx(path, "/") == (vim.fn.strlen(path)-1) then
        return vim.fn.strpart(path, 0, vim.fn.strlen(path)-1)
    end
    return path
end

-- strip the prefix from the path, usually to make a
-- relative path, and ensure leading '/'
function M.strip_path_prefix(prefix, path)
    local new = vim.fn.substitute(path, prefix, "", "")
    if vim.fn.strridx(new, '/') == -1 then
        new = '/' .. new
    end
    return new
end

return M


================================================
FILE: lua/litee/lib/util/window.lua
================================================
local lib_state         = require('litee.lib.state')
local lib_tree_config   = require('litee.lib.config').config["tree"]
local lib_icons         = require('litee.lib.icons')
local lib_hi            = require('litee.lib.highlights')

local M = {}

-- a convenience function for setting up tree window highlights
-- suitable for being ran inside a "post_window_create"
-- function.
--
-- see lib.tree.register_component for more details.
function M.set_tree_highlights()
    local icon_set = nil
    if lib_tree_config.icon_set == nil then
        icon_set = lib_icons["default"]
    else
        icon_set = lib_icons[lib_tree_config.icon_set]
    end
    -- set configured icon highlights
    for icon, hl in pairs(lib_icons.icon_hls) do
        vim.cmd(string.format("syn match %s /\\<%s\\>/", hl, icon_set[icon]))
    end
    -- set configured symbol highlight
    vim.cmd(string.format("syn match %s /%s/", lib_hi.hls.SymbolHL, [[\w]]))
    vim.cmd(string.format("syn match %s /%s/", lib_hi.hls.SymbolHL, [[\.]]))
    vim.cmd(string.format("syn match %s /%s/", lib_hi.hls.SymbolHL, [[\-]]))
    vim.cmd(string.format("syn match %s /%s/", lib_hi.hls.SymbolHL, [[\\_]]))
    -- set configured expanded indicator highlights
    vim.cmd(string.format("syn match %s /\\<%s\\>/", lib_hi.hls.ExpandedGuideHL, icon_set["Expanded"]))
    vim.cmd(string.format("syn match %s /\\<%s\\>/", lib_hi.hls.CollapsedGuideHL, icon_set["Collapsed"]))
    -- set configured indent guide highlight
    vim.cmd(string.format("syn match %s /\\<%s\\>/", lib_hi.hls.IndentGuideHL, icon_set["Guide"]))
end

-- inside_component_win is a helper functions which
-- tells the caller if the currently focused window
-- is a litee.nvim registered component window.
function M.inside_component_win()
    local tab = vim.api.nvim_get_current_tabpage()
    local win = vim.api.nvim_get_current_win()
    local state = lib_state.get_state(tab)
    if state == nil then
        return false
    end
    local active_components = lib_state.get_active_components(tab)

    local in_litee_panel = false
    for _, active_component in ipairs(active_components) do
        if win == state[active_component].win then
            in_litee_panel = true
        end
    end

    return in_litee_panel
end

-- is_component_win takes a tab and a window and returns
-- true if the provided window is a registered litee panel
-- window and false if not.
--
-- @param tab (int) A tab ID.
-- @param win (int) A window which resides in tab that
-- will be evaluated.
function M.is_component_win(tab, win)
    local active_components = lib_state.get_active_components(tab)
    local state = lib_state.get_state(tab)
    local is_litee_panel = false
    for _, active_component in ipairs(active_components) do
        if win == state[active_component].win then
            is_litee_panel = true
        end
    end
    return is_litee_panel
end

return M
Download .txt
gitextract_v9v813bt/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── README.md
├── doc/
│   ├── litee.txt
│   └── tags
└── lua/
    └── litee/
        └── lib/
            ├── commands.lua
            ├── config.lua
            ├── details/
            │   └── init.lua
            ├── highlights/
            │   ├── auto.lua
            │   └── init.lua
            ├── icons/
            │   └── init.lua
            ├── init.lua
            ├── jumps/
            │   └── init.lua
            ├── lsp/
            │   ├── hover.lua
            │   ├── init.lua
            │   └── wrappers.lua
            ├── navi/
            │   └── init.lua
            ├── notify/
            │   └── init.lua
            ├── panel/
            │   ├── autocmds.lua
            │   └── init.lua
            ├── state/
            │   ├── autocmds.lua
            │   └── init.lua
            ├── term/
            │   └── init.lua
            ├── tree/
            │   ├── init.lua
            │   ├── marshal/
            │   │   └── init.lua
            │   └── node.lua
            └── util/
                ├── buffer.lua
                ├── init.lua
                ├── path.lua
                └── window.lua
Condensed preview — 30 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (137K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 66,
    "preview": "# These are supported funding model platforms\n\ngithub: [ldelossa]\n"
  },
  {
    "path": ".gitignore",
    "chars": 9,
    "preview": "notes.md\n"
  },
  {
    "path": "README.md",
    "chars": 2485,
    "preview": "```\n██╗     ██╗████████╗███████╗███████╗   ███╗   ██╗██╗   ██╗██╗███╗   ███╗\n██║     ██║╚══██╔══╝██╔════╝██╔════╝   ████"
  },
  {
    "path": "doc/litee.txt",
    "chars": 22488,
    "preview": "*litee.nvim* litee.nvim\n\nAuthor:   Louis DeLosSantos <louis.delos@gmail.com>\nHomepage: <https://github.com/ldelossa/lite"
  },
  {
    "path": "doc/tags",
    "chars": 748,
    "preview": "after\tlitee.txt\t/*after*\nbefore\tlitee.txt\t/*before*\nlitee-contents\tlitee.txt\t/*litee-contents*\nlitee-intro\tlitee.txt\t/*l"
  },
  {
    "path": "lua/litee/lib/commands.lua",
    "chars": 568,
    "preview": "local M = {}\n\n-- commands will setup any Vim commands exported on litee.lib\n-- setup.\nfunction M.setup()\n    vim.cmd(\"co"
  },
  {
    "path": "lua/litee/lib/config.lua",
    "chars": 617,
    "preview": "local M = {}\n\n-- config is a global configuration object\n-- for each module in the litee library.\n--\n-- config for a par"
  },
  {
    "path": "lua/litee/lib/details/init.lua",
    "chars": 2023,
    "preview": "local M = {}\n\n-- a singleton float window for a details popup.\nlocal float_win = nil\n\n-- close_details_popups closes the"
  },
  {
    "path": "lua/litee/lib/highlights/auto.lua",
    "chars": 1869,
    "preview": "local lib_util  = require('litee.lib.util')\nlocal lib_hi    = require('litee.lib.highlights')\n\nlocal M = {}\n\n-- the curr"
  },
  {
    "path": "lua/litee/lib/highlights/init.lua",
    "chars": 5463,
    "preview": "local M = {}\n\n-- hls is a map of UI specific highlights used\n-- by the litee.nvim library.\nM.hls = {\n    SymbolDetailHL "
  },
  {
    "path": "lua/litee/lib/icons/init.lua",
    "chars": 9566,
    "preview": "local M = {}\n\n-- a lot of these are yoinked from:\n-- https://github.com/onsails/lspkind-nvim/blob/master/lua/lspkind/ini"
  },
  {
    "path": "lua/litee/lib/init.lua",
    "chars": 2530,
    "preview": "local commands = require('litee.lib.commands')\nlocal config = require('litee.lib.config').config\nlocal lib_hi = require("
  },
  {
    "path": "lua/litee/lib/jumps/init.lua",
    "chars": 7640,
    "preview": "local config    = require('litee.lib.config').config\nlocal lib_hi    = require('litee.lib.highlights')\nlocal lib_panel ="
  },
  {
    "path": "lua/litee/lib/lsp/hover.lua",
    "chars": 2171,
    "preview": "local M = {}\n\nlocal float_win = nil\n\n-- close_hover_popups closes the created popup window\n-- if it exists.\nfunction M.c"
  },
  {
    "path": "lua/litee/lib/lsp/init.lua",
    "chars": 5515,
    "preview": "local lib_notify = require('litee.lib.notify')\nlocal lib_tree_node = require('litee.lib.tree.node')\n\nlocal M = {}\n\n-- mu"
  },
  {
    "path": "lua/litee/lib/lsp/wrappers.lua",
    "chars": 555,
    "preview": "local lib_notify = require('litee.lib.notify')\nlocal M = {}\n\nfunction M.buf_document_symbol()\n    lib_notify.notify_popu"
  },
  {
    "path": "lua/litee/lib/navi/init.lua",
    "chars": 1740,
    "preview": "local M = {}\n\n-- next moves the cursor in the window of the provided\n-- component_state forward\n--\n-- @param component_s"
  },
  {
    "path": "lua/litee/lib/notify/init.lua",
    "chars": 2218,
    "preview": "local notify_config = require('litee.lib.config').config[\"notify\"]\nlocal M = {}\n\nlocal float_wins = {}\n\nfunction M.close"
  },
  {
    "path": "lua/litee/lib/panel/autocmds.lua",
    "chars": 519,
    "preview": "local lib_state = require('litee.lib.state')\nlocal lib_panel = require('litee.lib.panel')\n\nlocal M = {}\n\nfunction M.on_r"
  },
  {
    "path": "lua/litee/lib/panel/init.lua",
    "chars": 18300,
    "preview": "local lib_state = require('litee.lib.state')\nlocal config = require('litee.lib.config').config\nlocal lib_notify = requir"
  },
  {
    "path": "lua/litee/lib/state/autocmds.lua",
    "chars": 393,
    "preview": "local lib_tree  = require('litee.lib.tree')\nlocal lib_state = require('litee.lib.state')\n\nlocal M = {}\n\nM.on_tab_closed "
  },
  {
    "path": "lua/litee/lib/state/init.lua",
    "chars": 3348,
    "preview": "local M = {}\n\n-- registry is a per-tab-page registry for\n-- state.\n--\n-- state defines information necessary for\n-- a UI"
  },
  {
    "path": "lua/litee/lib/term/init.lua",
    "chars": 4769,
    "preview": "local lib_panel = require('litee.lib.panel')\nlocal lib_state = require('litee.lib.state')\nlocal lib_util_buf = require('"
  },
  {
    "path": "lua/litee/lib/tree/init.lua",
    "chars": 10784,
    "preview": "local lib_marshal = require('litee.lib.tree.marshal')\n\nlocal M = {}\n\n-- registry keeps a mapping between tree handles\n--"
  },
  {
    "path": "lua/litee/lib/tree/marshal/init.lua",
    "chars": 6379,
    "preview": "local lib_util = require('litee.lib.util')\nlocal lib_hi    = require('litee.lib.highlights')\nlocal lib_tree_config = req"
  },
  {
    "path": "lua/litee/lib/tree/node.lua",
    "chars": 2010,
    "preview": "local M = {}\n\n-- new_node creates a polymorphic node\n-- which the caller can attach their own\n-- node specific fields to"
  },
  {
    "path": "lua/litee/lib/util/buffer.lua",
    "chars": 3956,
    "preview": "local M = {}\n\n\nlocal original_guicursor = \"\"\n-- hide_cursor will dynamically create the LTCursorHide hi and\n-- set the g"
  },
  {
    "path": "lua/litee/lib/util/init.lua",
    "chars": 3352,
    "preview": "local M = {}\n\nfunction M.absolute_path_from_uri(uri)\n    local uri_path = vim.fn.substitute(uri, \"file://\", \"\", \"\")\n    "
  },
  {
    "path": "lua/litee/lib/util/path.lua",
    "chars": 3169,
    "preview": "local M = {}\n\n-- safe_encode returns a string which is safe to\n-- use as a filesystem name.\n--\n-- this is helpful when e"
  },
  {
    "path": "lua/litee/lib/util/window.lua",
    "chars": 2902,
    "preview": "local lib_state         = require('litee.lib.state')\nlocal lib_tree_config   = require('litee.lib.config').config[\"tree\""
  }
]

About this extraction

This page contains the full source code of the ldelossa/litee.nvim GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 30 files (125.1 KB), approximately 32.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!