[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [ldelossa]\n"
  },
  {
    "path": ".gitignore",
    "content": "notes.md\n"
  },
  {
    "path": "README.md",
    "content": "```\n██╗     ██╗████████╗███████╗███████╗   ███╗   ██╗██╗   ██╗██╗███╗   ███╗\n██║     ██║╚══██╔══╝██╔════╝██╔════╝   ████╗  ██║██║   ██║██║████╗ ████║ Lightweight\n██║     ██║   ██║   █████╗  █████╗     ██╔██╗ ██║██║   ██║██║██╔████╔██║ Integrated\n██║     ██║   ██║   ██╔══╝  ██╔══╝     ██║╚██╗██║╚██╗ ██╔╝██║██║╚██╔╝██║ Text\n███████╗██║   ██║   ███████╗███████╗██╗██║ ╚████║ ╚████╔╝ ██║██║ ╚═╝ ██║ Editing\n╚══════╝╚═╝   ╚═╝   ╚══════╝╚══════╝╚═╝╚═╝  ╚═══╝  ╚═══╝  ╚═╝╚═╝     ╚═╝ Environment\n====================================================================================\n```\n\n![litee screenshot](./contrib/litee-screenshot.png)\n\n# litee.nvim\n\nLitee.nvim (pronounced lite) is a library for building \"IDE-lite\" experiences in Neovim. \n\nBy utilizing the \"litee\" library plugin authors can achieve a consistent experience\nacross separate plugins.\n\nThere are several official litee plugins which can act as a reference for implementing\nadditional.\n\n## Calltree\nhttps://github.com/ldelossa/litee-calltree.nvim\n\nAnalogous to VSCode's \"Call Hierarchy\" tool, this plugin exposes an explorable tree\nof incoming or outgoing calls for a given symbol. \n\nUnlike other Neovim plugins, the tree can be expanded and collapsed to discover \n\"callers-of-callers\" and \"callees-of-callees\" until you hit a leaf.\n\n## Symboltree\nhttps://github.com/ldelossa/litee-symboltree.nvim\n\nAnalogous to VSCode's \"Outline\" tool, this plugin exposes a live tree of document\nsymbols for the current file. \n\nThe tree is updated as you move around and change files.\n\n## Filetree\nhttps://github.com/ldelossa/litee-filetree.nvim\n\nAnalogous to VSCode's \"Explorer\", this plugin exposes a full feature file explorer \nwhich supports recursive copies, recursive moves, and proper renaming of a file \n(more on this in the appropriate section).\n\n## Bookmarks\nhttps://github.com/ldelossa/litee-bookmarks.nvim\n\nThis plugin exposes a way to create Bookmarks, pinnable areas of important\ncode, and organize them into one or more Notebooks.\n\nNotebooks allow you to open and close sets of Bookmarks depending on what\nyou're working on that day.\n\n# Usage\n\nlitee.nvim is a library which other plugins can important and use. \n\nThe library has it's own configuration and setup function which can be\nviewed in the `doc.txt`.\n\nAn example of configuring the library is below:\n\n```\nrequire('litee.lib').setup({\n    tree = {\n        icon_set = \"codicons\"\n    },\n    panel = {\n        orientation = \"left\",\n        panel_size  = 30\n    }\n})\n```\n"
  },
  {
    "path": "doc/litee.txt",
    "content": "*litee.nvim* litee.nvim\n\nAuthor:   Louis DeLosSantos <louis.delos@gmail.com>\nHomepage: <https://github.com/ldelossa/litee.nvim>\nLicense:  MIT license\n\n██╗     ██╗████████╗███████╗███████╗   ███╗   ██╗██╗   ██╗██╗███╗   ███╗\n██║     ██║╚══██╔══╝██╔════╝██╔════╝   ████╗  ██║██║   ██║██║████╗ ████║ Lightweight\n██║     ██║   ██║   █████╗  █████╗     ██╔██╗ ██║██║   ██║██║██╔████╔██║ Integrated\n██║     ██║   ██║   ██╔══╝  ██╔══╝     ██║╚██╗██║╚██╗ ██╔╝██║██║╚██╔╝██║ Text\n███████╗██║   ██║   ███████╗███████╗██╗██║ ╚████║ ╚████╔╝ ██║██║ ╚═╝ ██║ Editing\n╚══════╝╚═╝   ╚═╝   ╚══════╝╚══════╝╚═╝╚═╝  ╚═══╝  ╚═══╝  ╚═╝╚═╝     ╚═╝ Environment\n====================================================================================\nCONTENTS                                                            *litee-contents*\n\n  1     Intro..............................................|litee-intro|\n  2     Usage..............................................|litee-usage|\n  3     Library Modules................................|litee-libraries|  \n  4     lib/details..................................|litee-lib-details|  \n  5     lib/highlights............................|litee-lib-highlights|  \n  6     lib/icons......................................|litee-lib-icons|  \n  7     lib/jumps......................................|litee-lib-jumps|  \n  8     lib/lsp..........................................|litee-lib-lsp|  \n  9     lib/navi........................................|litee-lib-navi|  \n  10    lib/notify......................................|litee-lib-navi|  \n  11    lib/panel......................................|litee-lib-panel|  \n  12    lib/state......................................|litee-lib-state|  \n  13    lib/tree........................................|litee-lib-tree|  \n  14    lib/util........................................|litee-lib-util|  \n  15    lib/term........................................|litee-lib-term|  \n\n====================================================================================\nINTRODUCTION                                                           *litee-intro*\n\nLitee.nvim (pronounced lite) is a library for building \"IDE-lite\" experience in Neovim. \n\nBy utilizing the \"litee\" library plugin authors can achieve a consistent experience\nacross separate plugins.\n\nThere are several official litee plugins which can act as a reference for implementing\nadditional.\n\n- Calltree\nhttps://github.com/ldelossa/litee-calltree\n\nAnalogous to VSCode's \"Call Hierarchy\" tool, this feature exposes an explorable tree\nof incoming or outgoing calls for a given symbol. \n\nUnlike other Neovim plugins, the tree can be expanded and collapsed to discover \n\"callers-of-callers\" and \"callees-of-callees\" until you hit a leaf.\n\n- Symboltree\nhttps://github.com/ldelossa/litee-symboltree\n\nAnalogous to VSCode's \"Outline\" tool, this feature exposes a live tree of document\nsymbols for the current file. \n\nThe tree is updated as you move around and change files.\n\n- Filetree\nhttps://github.com/ldelossa/litee-filetree\n\nAnalogous to VSCode's \"Explorer\", this feature exposes a full feature file explorer \nwhich supports recursive copies, recursive moves, and proper renaming of a file \n(more on this in the appropriate section).\n\n====================================================================================\nUsage                                                                  *litee-usage*\n\nLitee.nvim exports a single lua module called \"lib\".\n\nInside \"lib\" are several sub-modules which expose a facility for plugin authors.\n\nEach lib will be covered in detail in their respective sections.\n\nThe library itself has a config object which configures each sub-module.\n\nThe configuration is structured like so (with defaults).\n>\n    M.config = {\n        icons = {},\n        jumps = {},\n        lsp = {},\n        navi = {},\n        notify = {\n            enabled = true,\n        },\n        panel = {\n            orientation = \"left\",\n            panel_size = 30,\n        },\n        state = {},\n        tree = {\n            icon_set = \"default\",\n            indent_guides = true\n        }\n    }\n<\nEach key of the configuration corresponds to a library sub-module.\n\nYou can apply configuration to litee/lib by way of it's setup method found\nin litee/lib/init.lua, for example:\n>\n    require('litee.lib').setup({\n        tree = {\n            icon_set = \"codicons\"\n        },\n        panel = {\n            orientation = \"top\",\n            panel_size  = 15\n        }\n    })\n<\nThe above overrides the default configuration options for the icon_set used in the\ntree sub-module and changes the panel sub-module's orientation and size.\n\nExample for custom icons:\n>\n    -- Provide a custom icon_set which will be merged with the default icon_set.\n    require('litee.lib').setup{\n        tree = { icon_set_custom = { Struct = \"s\" } }\n    }\n\n    -- You can even copy, paste the icon_set in `lib/icons/init.lua`, then\n    -- modify it and pass it to `icon_set_custom`.\n    local icon_set_custom = { ... }\n    require('litee.lib').setup{\n        tree = { icon_set_custom = icon_set_custom }\n    }\n\n    -- Provide a custom icon_set which will be merged with the specified icon_set\n    -- from `lib/icons/init.lua` by name.\n    require('litee.lib').setup{\n        tree = { icon_set_custom = { Struct = \"s\" }, icon_set = \"codicons\" }\n    }\n<\n====================================================================================\nlib/details                                                      *litee-lib-details*\n\nThe `details` library exports a consistent way to display and close a details\npop up window.\n\nThe contents of the `details` pop-up is provided by a `detail_func` passed\ninto the `details_popup` function. \n\nThus, the caller can determine what the details are for a particular node or \nplugin element.\n\nThe `details` object was designed to be used with a tree node, however passing\nin any type for the \"node\" argument will work as long as the associated \"detail_func\"\ncan parse the object and spit out a set of buffer lines.\n\nUse `close_details_popup()` to close the pop-up.\n\n====================================================================================\nlib/highlights                                                *litee-lib-highlights*\n\nThe `highlights` library defines the highlights used within the `litee` library,\nmethods for setting up the default highlights, and a sub-module for the \nauto-highlights features.\n\nThe following highlights are exported and can be defined for theme overriding.\n>\n    M.hls = {\n        SymbolDetailHL      = \"LTSymbolDetail\",\n        SymbolHL            = \"LTSymbol\",\n        SymbolJumpHL        = \"LTSymbolJump\",\n        SymbolJumpRefsHL    = \"LTSymbolJumpRefs\",\n        IndentGuideHL       = \"LTIndentGuide\",\n        ExpandedGuideHL     = \"LTExpandedGuide\",\n        CollapsedGuideHL    = \"LTCollapsedGuide\",\n        SelectFiletreeHL    = \"LTSelectFiletree\"\n    }\n<\nThe `auto` module provides a facility for highlighting areas of a source file\ngiven a node and a window. \n\nTODO: The `auto` module should not rely on \"lib_util.resolve_absolute_file_path\" \nand \"lib_util.resolve_location\", as these methods require us to understand the \ntypes of \"node\" a head of time. \n\n====================================================================================\nlib/icons                                                          *litee-lib-icons*\n\nThe `icons` library defines and exports icon sets which plugin authors may use\nfor a consistent experience. \n\nCurrently `codicons`, `simple`, `nerd` and `default` icons are exported.\n\nThe `default` icon set only supplies the stock UTF-8 icons necessary to display\nlitee's UI such as indent guides and tree symbols.\n\nUsers of this library can override the exported icon libraries during runtime to\nchange an icon from its default.\n\nThis library also exports a list of icon highlights which can be overriden.\n\nCheck out the source file `lib/icons/init.lua` for full details.\n\n====================================================================================\nlib/jumps                                                          *litee-lib-jumps*\n\nThe `jumps` library defines and exports functions which perform source file jumps\nto a specific \"location\" object. \n\nThe \"location\" object is specified by the LSP, see: \nhttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#location\n\nHighlights can be set within the jumped-to source window and can be cleared with the `set_jump_hl`\nmethod.\n\nTODO: refactor jumps library to no longer need \"lib_util.resolve_location\" - all location details\nshould be passed in.\n\n====================================================================================\nlib/lsp                                                              *litee-lib-lsp*\n\nThe `lsp` library holds methods specific to interacting with the native LSP \nlibrary. \n\nThis includes helpers for making various LSP requests, wrappers for LSP methods\nand a library for creating Hover pop-ups.\n\nThis is the library to use or contribute to if you need to interface with \nNeovim's native LSP libraries.\n\n====================================================================================\nlib/navi                                                            *litee-lib-navi*\n\nThe `navi` library is small and exports methods for progressing a cursor forward\nor backwards in a window which is registered with litee. \n\nTwo callbacks exist to perform actions before and after the cursor move. \nSee source file for details.\n\nSee `litee-lib-panel` for information on registration.\n\n====================================================================================\nlib/notify                                                          *litee-lib-notify*\n\nThe `notify` library produces pop-up notifications at the top right corner\nof the editor.\n\nMethods exist to create both persistent notifications and ones with configurable\ntimeouts, along with methods to close all notifications.\n\nCurrently, notifications stack on top of each other so only one is visible at a time.\n\n====================================================================================\nlib/panel                                                          *litee-lib-panel*\n\nThe `panel` library provides a consistent panel experience across plugins which\nutilizes the `litee.nvim` library. \n\nThe panel is akin to panels in JetBrains and VSCode IDEs. \n\nFor a plugin to integrate with the panel it must register itself with the panel\nand it also must utilize \"lib/state\" to store its runtime state.\n\nRuntime state holds information about a registered plugins windows, tab, buffer, \netc, and is formally defined in `lib/state`\n\nTo register a plugin with the panel the `litee.lib.panel.register_component` method\nmust be used. \n\nThis method requires a `pre_window_create` callback and optionally takes a \n`post_window_create` callback. \n\nThe `pre_window_create` callback must create a buffer for the plugin being \nregistered and write the buffer ID into the plugin's component state, which is \nan argument to this callback. The plugin is free to perform any other actions \nassociated with displaying its window, such as setting up autocommands or buffer options.\n\nThe `post_window_create` method is optional and when called Neovim is inside the \nnewly created window within the panel. The plugin is free to perform any in-window\nmanipulations such as setting syntax highlights or window options. \n\nThe panel also supports a feature dubbed \"PopOut\" panels. \n\n\"PopOut\" panels are floating windows which act as if you're \"popping out\" the \npanel window to a float, and will \"pop\" back into the panel when closed. \nThis is convenient for \"zooming\" into panel windows. \n\nAdditionally, the panel need not be visible for a \"PopOut\" panel to be displayed.\nMeaning, users of `litee.nvim` do not necessary need to interface with the panel, \nand can use only \"PopOut\" panels if they prefer, tho the plugin has to facilitate \nthis by calling the right `lib/panel` api functions.\n\nFor more info on \"PopOut\" panels see the \"popout_to\" function in `litee.lib.panel`.\n\nThe rest of the API footprint exists to display/hide/jump into the panel. \nSee the source code for full details.\n\n====================================================================================\nlib/state                                                          *litee-lib-state*\n\nThe `state` library provides a library for handling plugin state.\n\nLitee must keep track of when components (plugins) are displayed in the panel, \nif their windows are valid, if they have an associated tree handle, whether their\nbuffer is valid, etc... \n\nLikewise, plugins need a way to retrieve and store their own state in between \nfunction calls.\n\nThe `state` library acts a registry for this state and makes it retrievable both\nglobally and by components.\n\nA component should only mutate its own state, unless it positively knows what \nits doing. \n\nThe state structure looks as follows:\n>\n  {\n      \"componentA\" = {\n          buf = 0,\n          win = 0,\n          tab = 0,\n          tree = 0,\n          win_dimensions = {0, 0},\n          invoking_win = 0,\n          active_lsp_clients = {list of lsp clients},\n          (component specific fields)...\n      },\n      \"componentB\" = {\n          buf = 0,\n          win = 0,\n          tab = 0,\n          tree = 0,\n          win_dimensions = {0, 0},\n          invoking_win = 0,\n          active_lsp_clients = {list of lsp clients},\n          (component specific fields)...\n      }\n  }\n<\nWhen functions expect the full state the function parameter is typically \"state\" and when\nfunctions expect a component's stat (state[\"componentA\"] for example) the parameter\nis typically \"component_state\". \n\nIdeally all of a plugin's methods which interface with litee require a \"component_state\", \nand they should only touch their own state.\n\nAccessors methods for both global and component state exist in `lib/state` along with methods\nto write both types of state back to the registry.\n\nNeovim is single threaded and tables are references, so its actually pretty uncommon to\nwrite state back into the registry. The exception is when setting the initial component\nstate table in the global state table, performed by `put_component_state`\n\n`lib/state.lua` exports some helpful methods such as getting the component type for\na particular buffer ID. Like always, until I have time to document better, check out the\nsource for full details.\n\n====================================================================================\nlib/tree                                                            *litee-lib-tree*\n\nThe `tree` library implements a reusable tree which supports the expansion and \ncollapsing of nodes. \n\nA node in the tree has a core data structure which a plugin can tag on plugin-specific\ndata on. \n\nA node looks as follows and can be instantiated with the \"lib.tree.node.new_node()\"\nmethod.\n>\n  {\n      -- a non-unique display name for the node\n      name = name,\n      -- the depth of the node in the target tree\n      depth = depth,\n      -- a unique key used to identify the node when\n      -- placed into a tree\n      key = key,\n      -- a list of children nodes with recursive definitions.\n      children = {},\n      -- whether this node is expanded in its containing\n      -- tree.\n      expanded = false,\n  }\n<\nIts the caller's job to define each value ensuring the key for the node is unique within\nthe tree being built. \n\nThe `tree` lib itself is a registry where you request a tree and get back a handle to it.\n\nThe handle can be stored on a plugin's state object and stored in `lib/state` and it also\npassed to `lib/tree` methods to identify which tree is being acted upon.\n\nThe data structure which represents a tree looks like this:\n`{root = {}, depth_table = {}, kind = \"\", source_line_map = nil, buf_line_map = nil}`\n\nWhere root is an empty root node, depth_table is a flattened 2d array containing a list of nodes\nat a particular depth of the tree (useful for quick lookups), kind is the kind of tree defined\nby the caller, source_line_map is a mapping from a source code line to a node in the tree, and\nbuf_line_map is a mapping from a buffer line in the tree to a source code line.\n\nsource_line_map can only be realized if your node has a top level \"location\" key with an LSP\nspecified `location` structure as its value. \n\nBoth aforementioned maps make it possibe to map items in the tree to source code lines and \nvice versa. The best way to understand this is looking at the reference implementations of\n\"litee-filetree\", \"litee-calltree\", and \"litee-symboltree\".\n\nOnce a tree is created you can begin building its nodes. \n\nA tree is build by creating a root node and then a list of children.\n\nFor convenience, the `add_node` function will take a root and a list of children,\ncompute the children's depth, attach the children to the root, and add it to the tree.\n\nIt's important to understand that by using the `add_node` without further options, you\ndo not need to worry about the children node's depth fields, but you DO need to always\nset the root's depth field.\n\nWhen the `add_node` method receives a root node with its depth field of 0 it throws\naway the old tree and creates a new one. \n\nWhen the `add_node` method receives a root node with a depth greater then zero it can\ncompute its children's depths and will add this new root (of a sub-tree) to the existing\ntree at the appropriate depth.\n\nSometimes, the caller wants to build the entire tree with their own business logic and\nsimply use the `tree` library for marshaling into a Neovim buffer and other facilities \nsuch as expand and collapsing. If this is the case you can use the `external` flag \nto the 'add_node' method. \n\nWhen the `add_node` method sees the external flag is set to true, it performs no \nactions on the root and simply adds it to the tree structure outlined above. The\n`children` parameter is completely ignored.\n\nOnce the tree is built and all the desired nodes are added, you can write the tree\nto a buffer with the \"write_tree\" method. \n\n`function M.write_tree(buf, tree, marshal_func, no_guide_leaf)`\n\nThe write_tree method takes a buffer ID to write too, a tree ID to write, a marshal_func\nwhich is called for each node and returns the necessary strings which will make up the \nbuffer line in the tree, and a \"no_guide_leaf\" flag. See the method's documentation\nfor marshal_func details.\n\nThe `no_guide_leaf` flag tells the `write_tree` method that when a node is expanded,\nand it has no children, leave off the \"expanded\" guide (the down arrow showing its expanded). \n\nThis is a nice effect for some trees and a helper method exists if your plugin will always\nuse this method `function M.write_tree_no_guide_leaf(buf, tree, marshal_func)`. \n\nMake note, the `write_tree` function can only determine a leaf *after* the node is expanded,\nfor example, a node is collapsed, you expand it, it has no children, no expanded guide is shown.\n\nThere are times where the caller can determine an item is a leaf *before* its expanded, for example,\nin a file tree, we know a regular file does not need an expand guide. \n\nTo accomplish this the `marshal_func` suports returning an override for the expand guide as its \nvery last argument. If returned, this symbol is used instead of the expand guide `write_tree` \nwould use on its own accord. `litee-filetree` uses this to simply return a \" \" when it sees\na regular file.\n\nThere is a method, `function M.marshal_line(linenr, handle)', which takes a tree buffer's linenr\nand a tree handle and returns the corresponding node.\n\nA small note on the depth_table. A depth_table is a flattened 2d array which hold a list of nodes\nat a particular depth. This makes getting nodes at a particular depth very easy and (maybe...?) \nfaster then a tree traversal. A depth_table is available after any initial and all subsequent\n`add_node` calls.\n\nVarious methods exist in the library for manipulating the tree such as collapsing nodes and \nremoving subtrees. Take a look at the source code to see what is available.\n\n====================================================================================\nlib/util                                                            *litee-lib-util*\n\nLib `util` is a dumping ground for various helper functions and utilities. \n\nLib `util` exports several helpful sub-libraries. \n\n`lib.util.window` For helper functions around Neovim windows\n`lib.util.buffer` For helper functions around Neovim buffers\n`lib.util.path`   For helper functions dealing with file system paths (only linux right now.)\n\n====================================================================================\nlib/term                                                            *litee-lib-term*\n\nLib `term` exports a method for opening a Neovim native terminal that is aware\nof `litee.nvim` environment. \n\nThis terminal can be opened on the top or bottom and is controlled by the \"term\"\nconfiguration block in the `lib.config` module.\n\n>\n    term = {\n        -- can be  \"top\" or \"bottom\"\n        position = \"bottom\",\n        -- the initial size of the terminal\n        term_size = 15,\n        -- if true maps arrow keys to window resize\n        -- commands.\n        map_resize_keys = true,\n    },\n<\n\nThe terminal creates two \"terminal\" mode key bindings. \n>\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>v\", \"<cmd>lua require('configs.terminal').terminal_vsplit()<cr>\", opts)\n\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>n\", \"<C-\\\\><C-n>\", opts)\n\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>h\", \"<C-\\\\><C-n> <C-w>h\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>j\", \"<C-\\\\><C-n> <C-w>j\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>k\", \"<C-\\\\><C-n> <C-w>k\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>l\", \"<C-\\\\><C-n> <C-w>l\", opts)\n<\nThe first one will open another terminal in a vsplit relative to the terminal you're issuing\nthe command in.\n\nThe second is a helper that puts your terminal back into normal mode. \n\nThe final set are short-cuts for jumping out of the terminal into other windows.\n\nBe aware, these mappins will only work when your Vim mode is \"terminal\" which is when\ninput is being forwarded directly to the shell. If you are in normal mode (the shell is just\na buffer of lines at that point) the mappins will revert back to normal mode mappings.\n\nThe term can be triggered open with the \"LTTerm\" user command.\n\nvim:ft=help\n"
  },
  {
    "path": "doc/tags",
    "content": "after\tlitee.txt\t/*after*\nbefore\tlitee.txt\t/*before*\nlitee-contents\tlitee.txt\t/*litee-contents*\nlitee-intro\tlitee.txt\t/*litee-intro*\nlitee-lib-details\tlitee.txt\t/*litee-lib-details*\nlitee-lib-highlights\tlitee.txt\t/*litee-lib-highlights*\nlitee-lib-icons\tlitee.txt\t/*litee-lib-icons*\nlitee-lib-jumps\tlitee.txt\t/*litee-lib-jumps*\nlitee-lib-lsp\tlitee.txt\t/*litee-lib-lsp*\nlitee-lib-navi\tlitee.txt\t/*litee-lib-navi*\nlitee-lib-notify\tlitee.txt\t/*litee-lib-notify*\nlitee-lib-panel\tlitee.txt\t/*litee-lib-panel*\nlitee-lib-state\tlitee.txt\t/*litee-lib-state*\nlitee-lib-term\tlitee.txt\t/*litee-lib-term*\nlitee-lib-tree\tlitee.txt\t/*litee-lib-tree*\nlitee-lib-util\tlitee.txt\t/*litee-lib-util*\nlitee-usage\tlitee.txt\t/*litee-usage*\nlitee.nvim\tlitee.txt\t/*litee.nvim*\n"
  },
  {
    "path": "lua/litee/lib/commands.lua",
    "content": "local M = {}\n\n-- commands will setup any Vim commands exported on litee.lib\n-- setup.\nfunction M.setup()\n    vim.cmd(\"command! LTPanel           lua require('litee.lib.panel').toggle_panel()\")\n    vim.cmd(\"command! LTTerm            lua require('litee.lib.term').terminal()\")\n    vim.cmd(\"command! LTListTerms       lua require('litee.lib.term').list_terminals()\")\n    vim.cmd(\"command! LTClearJumpHL     lua require('litee.lib.jumps').set_jump_hl(false)\")\n    vim.cmd(\"command! LTClosePanelPopOut lua require('litee.lib.panel').close_current_popout()\")\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/config.lua",
    "content": "local M = {}\n\n-- config is a global configuration object\n-- for each module in the litee library.\n--\n-- config for a particular module is keyed\n-- by the module's directory name.\nM.config = {\n    icons = {},\n    jumps = {},\n    lsp = {},\n    navi = {},\n    notify = {\n        enabled = true,\n    },\n    panel = {\n        orientation = \"left\",\n        panel_size = 30,\n    },\n    state = {},\n    term = {\n        position = \"bottom\",\n        term_size = 15,\n        map_resize_keys = true,\n    },\n    tree = {\n        icon_set = \"default\",\n        icon_set_custom = nil,\n        indent_guides = true\n    }\n}\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/details/init.lua",
    "content": "local M = {}\n\n-- a singleton float window for a details popup.\nlocal float_win = nil\n\n-- close_details_popups closes the created popup window\n-- if it exists.\nfunction M.close_details_popup()\n    if float_win ~= nil and\n        vim.api.nvim_win_is_valid(float_win) then\n        vim.api.nvim_win_close(float_win, true)\n        float_win = nil\n    end\nend\n\n-- details_popup creates a popup window showing futher details\n-- about a symbol.\n--\n-- @param state (table) The global state as defined by\n-- the lib/state library.\n-- @param node (table) A node passed to `detail_func` representing\n-- the item being described.\n-- @param detail_func function(state, node) A function called with the\n-- provided state and node that returns a list of buffer lines.\n-- The function must evaluate both arguments and return a list of buffer\n-- lines which describe any details about the node the caller defines.\nfunction M.details_popup(state, node, detail_func)\n    local buf = vim.api.nvim_create_buf(false, true)\n    if buf == 0 then\n        vim.api.nvim_err_writeln(\"details_popup: could not create details buffer\")\n        return\n    end\n    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'delete')\n    vim.api.nvim_buf_set_option(buf, 'syntax', 'yaml')\n\n    local lines = detail_func(state, node)\n    if lines == nil then\n        return\n    end\n\n    local width = 20\n    for _, line in ipairs(lines) do\n        local line_width = vim.fn.strdisplaywidth(line)\n        if line_width > width then\n            width = line_width\n        end\n    end\n\n    vim.api.nvim_buf_set_option(buf, 'modifiable', true)\n    vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)\n    vim.api.nvim_buf_set_option(buf, 'modifiable', false)\n    local popup_conf = vim.lsp.util.make_floating_popup_options(\n            width,\n            #lines,\n            {\n                border= \"rounded\",\n                focusable= false,\n                zindex = 99,\n            }\n    )\n    float_win = vim.api.nvim_open_win(buf, false, popup_conf)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/highlights/auto.lua",
    "content": "local lib_util  = require('litee.lib.util')\nlocal lib_hi    = require('litee.lib.highlights')\n\nlocal M = {}\n\n-- the current highlight used for auto-highlighting\nM.higlight_ns = vim.api.nvim_create_namespace(\"calltree-hl\")\n\n-- highlight will set a highlight on the source code\n-- lines the provided node represents if the invoking_win\n-- holds a buffer to said file.\n--\n-- @param node (table) The element representing a source\n-- code symbol or element. This function requires the node\n-- to have a top level \".location\" field.\n-- @param set (bool) If false any highlights which were\n-- previously set are cleared. If true, highlights will\n-- be created.\n-- @param win (int) A window handle to the window\n-- being evaluated for highlighting.\nfunction M.highlight(node, set, win)\n    if not vim.api.nvim_win_is_valid(win) then\n        return\n    end\n    local buf = vim.api.nvim_win_get_buf(win)\n    if not vim.api.nvim_buf_is_valid(buf) then\n        return\n    end\n    vim.api.nvim_buf_clear_namespace(\n        buf,\n        M.higlight_ns,\n        0,\n        -1\n    )\n    if not set then\n        return\n    end\n\n    local location = node.location\n    if location == nil then\n        return\n    end\n    local range = location.range\n\n    if range[\"end\"] == nil then\n        return\n    end\n\n    -- make sure URIs match before setting highlight\n    local invoking_buf = vim.api.nvim_win_get_buf(win)\n    local cur_file = vim.api.nvim_buf_get_name(invoking_buf)\n    local symbol_path = lib_util.absolute_path_from_uri(location.uri)\n    if cur_file ~= symbol_path then\n        return\n    end\n\n    vim.api.nvim_buf_add_highlight(\n        buf,\n        M.higlight_ns,\n        lib_hi.hls.SymbolJumpHL,\n        range[\"start\"].line,\n        range[\"start\"].character,\n        range[\"end\"].character\n    )\n    vim.api.nvim_win_set_cursor(win, {range[\"start\"].line+1, 0})\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/highlights/init.lua",
    "content": "local M = {}\n\n-- hls is a map of UI specific highlights used\n-- by the litee.nvim library.\nM.hls = {\n    SymbolDetailHL      = \"LTSymbolDetail\",\n    SymbolHL            = \"LTSymbol\",\n    SymbolJumpHL        = \"LTSymbolJump\",\n    SymbolJumpRefsHL    = \"LTSymbolJumpRefs\",\n    IndentGuideHL       = \"LTIndentGuide\",\n    ExpandedGuideHL     = \"LTExpandedGuide\",\n    CollapsedGuideHL    = \"LTCollapsedGuide\",\n    SelectFiletreeHL    = \"LTSelectFiletree\",\n    NormalSB            = \"LTNormalSB\"\n}\n\n-- setup_default_highlights configures a list of default\n-- highlights for the litee.nvim library.\nfunction M.setup_default_highlights()\n    local dark = {\n        LTBoolean              = 'hi LTBoolean                guifg=#0087af guibg=None',\n        LTConstant             = 'hi LTConstant               guifg=#0087af guibg=None',\n        LTConstructor          = 'hi LTConstructor            guifg=#4DC5C6 guibg=None',\n        LTField                = 'hi LTField                  guifg=#0087af guibg=None',\n        LTFunction             = 'hi LTFunction               guifg=#988ACF guibg=None',\n        LTMethod               = 'hi LTMethod                 guifg=#0087af guibg=None',\n        LTNamespace            = 'hi LTNamespace              guifg=#87af87 guibg=None',\n        LTNumber               = 'hi LTNumber                 guifg=#9b885c guibg=None',\n        LTOperator             = 'hi LTOperator               guifg=#988ACF guibg=None',\n        LTParameter            = 'hi LTParameter              guifg=#988ACF guibg=None',\n        LTParameterReference   = 'hi LTParameterReference     guifg=#4DC5C6 guibg=None',\n        LTString               = 'hi LTString                 guifg=#af5f5f guibg=None',\n        LTSymbol               = 'hi LTSymbol                 guifg=#87afd7 ',\n        LTSymbolDetail         = 'hi LTSymbolDetail           ctermfg=024 cterm=italic guifg=#988ACF gui=italic',\n        LTSymbolJump           = 'hi LTSymbolJump             ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#87afd7 gui=italic,bold',\n        LTSymbolJumpRefs       = 'hi LTSymbolJumpRefs         ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#9b885c gui=italic,bold',\n        LTType                 = 'hi LTType                   guifg=#9b885c guibg=None',\n        LTURI                  = 'hi LTURI                    guifg=#988ACF guibg=None',\n        LTIndentGuide          = 'hi LTIndentGuide            guifg=None    guibg=None',\n        LTExpandedGuide        = 'hi LTExpandedGuide          guifg=None    guibg=None',\n        LTCollapsedGuide       = 'hi LTCollapsedGuide         guifg=None    guibg=None',\n        LTSelectFiletree       = 'hi LTSelectFiletree ctermbg=131  ctermfg=246 cterm=None guibg=#af5f5f guifg=#e4e4e4 gui=None'\n    }\n    local light = {\n        LTBoolean               = 'hi LTBoolean                guifg=#005f87 guibg=None',\n        LTConstant              = 'hi LTConstant               guifg=#005f87 guibg=None',\n        LTConstructor           = 'hi LTConstructor            guifg=#9b885c guibg=None',\n        LTField                 = 'hi LTField                  guifg=#005f87 guibg=None',\n        LTFunction              = 'hi LTFunction               guifg=#806CCF guibg=None',\n        LTMethod                = 'hi LTMethod                 guifg=#005f87 guibg=None',\n        LTNamespace             = 'hi LTNamespace              guifg=#87af87 guibg=None',\n        LTNumber                = 'hi LTNumber                 guifg=#9b885c guibg=None',\n        LTOperator              = 'hi LTOperator               guifg=#806CCF guibg=None',\n        LTParameter             = 'hi LTParameter              guifg=#806CCF guibg=None',\n        LTParameterReference    = 'hi LTParameterReference     guifg=#268889 guibg=None',\n        LTString                = 'hi LTString                 guifg=#af5f5f guibg=None',\n        LTSymbol                = 'hi LTSymbol                 guifg=#806CCF gui=underline',\n        LTSymbolDetail          = 'hi LTSymbolDetail           ctermfg=024 cterm=italic guifg=#005f87 gui=italic',\n        LTSymbolJump            = 'hi LTSymbolJump             ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#87afd7 gui=italic,bold',\n        LTSymbolJumpRefs        = 'hi LTSymbolJumpRefs         ctermfg=015 ctermbg=110 cterm=italic,bold,underline   guifg=#464646 guibg=#9b885c gui=italic,bold',\n        LTType                  = 'hi LTType                   guifg=#268889 guibg=None',\n        LTURI                   = 'hi LTURI                    guifg=#806CCF guibg=None',\n        LTIndentGuide           = 'hi LTIndentGuide            guifg=None    guibg=None',\n        LTExpandedGuide         = 'hi LTExpandedGuide          guifg=None    guibg=None',\n        LTCollapsedGuide        = 'hi LTCollapsedGuide         guifg=None    guibg=None',\n        LTSelectFiletree        = 'hi LTSelectFiletree ctermbg=131  ctermfg=246 cterm=None guibg=#af5f5f guifg=#e4e4e4 gui=None'\n    }\n    local bg = vim.api.nvim_get_option(\"background\")\n    if bg == \"dark\" then\n        for hl_name, hl in pairs(dark) do\n            if vim.fn.hlexists(hl_name) == 0 then\n                vim.cmd(hl)\n            end\n        end\n    end\n    if bg == \"light\" then\n        for hl_name, hl in pairs(light) do\n            if vim.fn.hlexists(hl_name) == 0 then\n                vim.cmd(hl)\n            end\n        end\n    end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/icons/init.lua",
    "content": "local M = {}\n\n-- a lot of these are yoinked from:\n-- https://github.com/onsails/lspkind-nvim/blob/master/lua/lspkind/init.lua\nM.nerd = {\n    Account         = '',\n    Array           = \"\",\n    Bookmark        = \"\",\n    Boolean         = \"\",\n    Calendar        = '',\n    Check           = '',\n    CheckAll        = '',\n    Circle          = '',\n    CircleFilled    = '',\n    CirclePause     = '',\n    CircleSlash     = '',\n    CircleStop      = '',\n    Class           = \"ﴯ\",\n    Collapsed       = \"\",\n    Color           = \"\",\n    Comment         = '',\n    Constant        = \"\",\n    Constructor     = \"\",\n    DiffAdded       = '',\n    Enum            = \"\",\n    EnumMember      = \"\",\n    Event           = \"\",\n    Expanded        = \"\",\n    Field           = \"ﰠ\",\n    File            = \"\",\n    Folder          = \"\",\n    Function        = \"\",\n    GitBranch       = '',\n    GitCommit       = 'ﰖ',\n    GitCompare      = '',\n    GitIssue        = '',\n    GitMerge        = 'שּׁ',\n    GitPullRequest  = '',\n    GitRepo         = '',\n    IndentGuide     = \"⎸\",\n    Info            = '',\n    Interface       = \"\",\n    Key             = \"\",\n    Keyword         = \"\",\n    Method          = \"\",\n    Module          = \"\",\n    MultiComment    = '',\n    Namespace       = \"\",\n    Notebook        = \"ﴬ\",\n    Null            = \"ﳠ\",\n    Number          = \"\",\n    Object          = \"\",\n    Operator        = \"\",\n    Package         = \"\",\n    Pass            = '',\n    PassFilled      = '',\n    Pencil          = '',\n    Property        = \"ﰠ\",\n    Reference       = \"\",\n    Separator       = \"•\",\n    Snippet         = \"\",\n    Space           = \" \",\n    String          = \"\",\n    Struct          = \"פּ\",\n    Text            = \"\",\n    TypeParameter   = \"\",\n    Unit            = \"塞\",\n    Value           = \"\",\n    Variable        = \"\",\n}\n\nM.codicons = {\n    Account         = '',\n    Array           = \"\",\n    Bookmark        = \"\",\n    Boolean         = \"\",\n    Calendar        = '',\n    Check           = '',\n    CheckAll        = '',\n    Circle          = '',\n    CircleFilled    = '',\n    CirclePause     = '',\n    CircleSlash     = '',\n    CircleStop      = '',\n    Class           = \"\",\n    Collapsed       = \"\",\n    Color           = \"\",\n    Comment         = '',\n    CommentExclaim  = '',\n    Constant        = \"\",\n    Constructor     = \"\",\n    DiffAdded       = '',\n    Enum            = \"\",\n    EnumMember      = \"\",\n    Event           = \"\",\n    Expanded        = \"\",\n    Field           = \"\",\n    File            = \"\",\n    Folder          = \"\",\n    Function        = \"\",\n    GitBranch       = '',\n    GitCommit       = '',\n    GitCompare      = '',\n    GitIssue        = '',\n    GitMerge        = '',\n    GitPullRequest  = '',\n    GitRepo         = '',\n    History         = '',\n    IndentGuide     = \"⎸\",\n    Info            = '',\n    Interface       = \"\",\n    Key             = \"\",\n    Keyword         = \"\",\n    Method          = \"\",\n    Module          = \"\",\n    MultiComment    = '',\n    Namespace       = \"\",\n    Notebook        = \"\",\n    Notification    = '',\n    Null            = \"\",\n    Number          = \"\",\n    Object          = \"\",\n    Operator        = \"\",\n    Package         = \"\",\n    Pass            = '',\n    PassFilled      = '',\n    Pencil          = '',\n    Property        = \"\",\n    Reference       = \"\",\n    RequestChanges  = '',\n    Separator       = \"•\",\n    Snippet         = \"\",\n    Space           = \" \",\n    String          = \"\",\n    Struct          = \"\",\n    Sync            = '',\n    Text            = \"\",\n    TypeParameter   = \"\",\n    Unit            = \"\",\n    Value           = \"\",\n    Variable        = \"\",\n}\n\nM.default = {\n    Account         = \"🗣\",\n    Array           = \"\\\\[\\\\]\",\n    Bookmark        = \"🏷\",\n    Boolean         = \"∧\",\n    Calendar        = '🗓',\n    Check           = '✓',\n    CheckAll        = '🗸🗸',\n    Circle          = '🞆',\n    CircleFilled    = '●',\n    CirclePause     = '⦷',\n    CircleSlash     = '⊘',\n    CircleStop      = '⦻',\n    Class           = \"c\",\n    Collapsed       = \"▶\",\n    Color           = \"🖌\",\n    Comment         = '🗩',\n    CommentExclaim  = '🗩',\n    Constant        = \"c\",\n    Constructor     = \"c\",\n    DiffAdded       = '+',\n    Enum            = \"Ε\",\n    EnumMember      = \"Ε\",\n    Event           = \"🗲\",\n    Expanded        = \"▼\",\n    Field           = \"𝐟\",\n    File            = \"🗀\",\n    Folder          = \"🗁\",\n    Function        = \"ƒ\",\n    GitBranch       = ' ',\n    GitCommit       = '⫰',\n    GitCompare      = '⤄',\n    GitIssue        = '⊙',\n    GitMerge        = '⫰',\n    GitPullRequest  = '⬰',\n    GitRepo         = '🕮',\n    History         = '⟲',\n    IndentGuide     = \"⎸\",\n    Info            = '🛈',\n    Interface       = \"I\",\n    Key             = \"\",\n    Keyword         = \"\",\n    Method          = \"\",\n    Module          = \"M\",\n    MultiComment    = '🗩',\n    Namespace       = \"N\",\n    Notebook        = \"🕮\",\n    Notification    = '🕭',\n    Null            = \"null\",\n    Number          = \"#\",\n    Object          = \"{}\",\n    Operator        = \"0\",\n    Package         = \"{}\",\n    Pass            = '🗸',\n    PassFilled      = '🗸',\n    Pencil          = '',\n    Property        = \"🛠\",\n    Reference       = \"⛉\",\n    RequestChanges  = '⨪',\n    Separator       = \"•\",\n    Space           = \" \",\n    String          = \"\\\"\",\n    Struct          = \"struct\",\n    Sync            = '🗘',\n    Text            = \"\\\"\",\n    TypeParameter   = \"T\",\n    Unit            = \"U\",\n    Value           = \"v\",\n    Variable        = \"V\",\n}\n\nM.simple = {\n    Account         = \"A\",\n    Array           = \"\\\\[\\\\]\",\n    Bookmark        = \"BM\",\n    Boolean         = \"bool\",\n    Calendar        = 'cal',\n    Check           = 'x',\n    CheckAll        = 'xx',\n    Circle          = 'o',\n    CircleFilled    = 'O',\n    CirclePause     = 'P',\n    CircleSlash     = 'ø',\n    CircleStop      = 'stop',\n    Class           = \"class\",\n    Collapsed       = \">\",\n    Color           = \"color\",\n    Comment         = 'c',\n    CommentExclaim  = 'c!',\n    Constant        = \"c\",\n    Constructor     = \"C\",\n    DiffAdded       = '+',\n    Enum            = \"Ε\",\n    EnumMember      = \"Ε\",\n    Event           = \"e\",\n    Expanded        = \"v\",\n    Field           = \"f\",\n    File            = \"F\",\n    Folder          = \"D\",\n    Function        = \"fn\",\n    GitBranch       = 'br',\n    GitCommit       = 'ci',\n    GitCompare      = 'cmp',\n    GitIssue        = 'I',\n    GitMerge        = 'M',\n    GitPullRequest  = 'PR',\n    GitRepo         = 'R',\n    History         = 'H',\n    IndentGuide     = \" \",\n    Info            = 'i',\n    Interface       = \"I\",\n    Key             = \"k\",\n    Keyword         = \"kw\",\n    Method          = \"m\",\n    Module          = \"M\",\n    MultiComment    = '#',\n    Namespace       = \"NS\",\n    Notebook        = \"NB\",\n    Notification    = 'N',\n    Null            = \"null\",\n    Number          = \"#\",\n    Object          = \"{}\",\n    Operator        = \"op\",\n    Package         = \"{}\",\n    Pass            = 'y',\n    PassFilled      = 'yy',\n    Pencil          = 'e',\n    Property        = \"P\",\n    Reference       = \"&\",\n    RequestChanges  = '-',\n    Separator       = \".\",\n    Space           = \" \",\n    String          = \"\\\"\",\n    Struct          = \"S\",\n    Sync            = 's',\n    Text            = \"\\\"\",\n    TypeParameter   = \"T\",\n    Unit            = \"U\",\n    Value           = \"v\",\n    Variable        = \"V\",\n}\n\nM.icon_hls = {\n    Array           = \"LTConstant\",\n    Boolean         = \"LTBoolean\",\n    Class           = \"LTType\",\n    Constant        = \"LTConstant\",\n    Constructor     = \"LTFunction\",\n    Enum            = \"LTType\",\n    EnumMember      = \"LTField\",\n    Event           = \"LTType\",\n    Field           = \"LTField\",\n    File            = \"LTURI\",\n    Folder          = \"LTNamespace\",\n    Function        = \"LTFunction\",\n    Interface       = \"LTType\",\n    Key             = \"LTType\",\n    Keyword         = \"LTConstant\",\n    Method          = \"LTFunction\",\n    Module          = \"LTNamespace\",\n    Namespace       = \"LTNamespace\",\n    Null            = \"LTType\",\n    Number          = \"LTNumber\",\n    Object          = \"LTType\",\n    Operator        = \"LTOperator\",\n    Package         = \"LTNamespace\",\n    Property        = \"LTMethod\",\n    Reference       = \"LTType\",\n    Snippet         = \"LTString\",\n    String          = \"LTString\",\n    Struct          = \"LTType\",\n    Text            = \"LTString\",\n    TypeParameter   = \"LTParameter\",\n    Unit            = \"LTType\",\n    Value           = \"LTType\",\n    Variable        = \"LTConstant\",\n\n    Info            = 'LTInfo',\n    Pass            = 'LTSuccess',\n    PassFilled      = 'LTSuccess',\n    Account         = 'LTAccount',\n    Check           = 'LTSuccess',\n    CheckAll        = 'LTSuccess',\n    CircleFilled    = 'LTDefault',\n    Circle          = 'LTDefault',\n    CircleSlash     = 'LTWarning',\n    GitCompare      = 'LTGitCompare',\n    GitBranch       = 'LTGitBranch',\n    GitPullRequest  = 'LTGitPullRequest',\n    CircleStop      = 'LTFailure',\n    DiffAdded       = 'LTDiffAdded',\n    CirclePause     = 'LTWarning',\n    GitCommit       = 'LTGitCommit',\n\n    Comment         = 'LTComment',\n    MultiComment    = 'LTMultiComment',\n\n    Calendar        = 'LTDefault',\n    Pencil          = 'LTWarning',\n\n    History         = 'LTWarning',\n    Sync            = 'LTWarning',\n    CommentExclaim  = 'LTWarning',\n    RequestChanges  = 'LTFailure',\n    Notification    = 'LTDiffAdded'\n}\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/init.lua",
    "content": "local commands = require('litee.lib.commands')\nlocal config = require('litee.lib.config').config\nlocal lib_hi = require('litee.lib.highlights')\nlocal lib_icons = require('litee.lib.icons')\n\nlocal M = {}\n\n-- Once set up, `M.icon_set` must be a non-nil table.\nM.icon_set = nil\n\nlocal function icon_set()\n    local tree = config.tree\n    local base = lib_icons[tree.icon_set] or lib_icons[\"default\"]\n    local icon_set = nil\n    if tree.icon_set_custom ~= nil then\n        icon_set = tree.icon_set_custom\n        -- merge custom icon with the default\n        for key, val in pairs(base) do\n            icon_set[key] = icon_set[key] or base[key]\n        end\n    else\n        icon_set = base\n    end\n    M.icon_set = icon_set\nend\n\n-- If a custom icon_set (table) is provided by the user,\n-- `M.icon_set` will be updated and returned.\n-- A user can use the icons from `lib_icons`\n-- via providing a key name instead of a custom icon_set (table).\n-- When both arguments are provided, the custom icon_set is merged\n-- with the icons given by its name from `lib_icons`.\nfunction M.icon_set_update(custom, icon_key)\n    local icon_set = nil\n    if custom ~= nil then\n        icon_set = icon_key and lib_icons[icon_key] or M.icon_set\n        for key, val in pairs(custom) do\n            icon_set[key] = custom[key]\n        end\n    else\n        icon_set = lib_icons[icon_key] or lib_icons[\"default\"]\n    end\n    return icon_set\nend\n\nlocal function merge_subconfig(component, user_subconfig)\n    local subconfig = config[component]\n    if subconfig == nil then\n        return\n    end\n\n    for key, val in pairs(user_subconfig) do\n        subconfig[key] = val\n    end\nend\n\nfunction M.setup(user_config)\n    if user_config ~= nil then\n        for component, user_subconfig in pairs(user_config) do\n            merge_subconfig(component, user_subconfig)\n        end\n    end\n\n    -- setup icon_set\n    icon_set()\n\n    -- setup default highlights\n    lib_hi.setup_default_highlights()\n\n    -- setup commands\n    commands.setup()\n\n    -- au to close popup with cursor moves or buffer is closed.\n    vim.cmd(\"au CursorMoved,BufWinLeave,WinLeave * lua require('litee.lib.util.buffer').close_all_popups()\")\n\n    -- on resize cycle the panel to re-adjust window sizes.\n    vim.cmd(\"au VimResized * lua require('litee.lib.panel.autocmds').on_resize()\")\n\n    -- will clean out any tree data for a tab when closed. only necessary\n    vim.cmd([[au TabClosed * lua require('litee.lib.state.autocmds').on_tab_closed(vim.fn.expand('<afile>'))]])\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/jumps/init.lua",
    "content": "local config    = require('litee.lib.config').config\nlocal lib_hi    = require('litee.lib.highlights')\nlocal lib_panel = require('litee.lib.panel')\n\nlocal M = {}\n\n-- the current highlight source, reset on jumps\nM.jump_higlight_ns = vim.api.nvim_create_namespace(\"calltree-jump\")\n-- the buffer we highlighted last.\nM.last_highlighted_buffer = nil\n\n-- move_or_create will a attempt to move from the\n-- calltree ui window to the nearest editor window\n--\n-- if the move fails, assumingly because no other window\n-- exists, a new window will be created.\n--\n-- @param orientation (string) The orientation of the\n-- surrouning plugin UI to make jumps intuitive.\n-- This is typically the orientation of the litee.nvim\n-- panel. Valid arguments are \"left, right, top, bottom\".\nlocal function move_or_create(orientation)\n    local cur_win = vim.api.nvim_get_current_win()\n    if orientation == \"left\" then\n        vim.cmd('wincmd l')\n    elseif orientation == \"right\" then\n        vim.cmd('wincmd h')\n    elseif orientation == \"top\" then\n        vim.cmd('wincmd j')\n    elseif orientation == \"bottom\" then\n        vim.cmd('wincmd k')\n    end\n    if cur_win == vim.api.nvim_get_current_win() then\n        if orientation == \"left\" then\n            vim.cmd(\"botright vsplit\")\n            return true\n        elseif orientation == \"right\" then\n            vim.cmd(\"topleft vsplit\")\n            return true\n        elseif orientation == \"top\" then\n            vim.cmd(\"topleft split\")\n            return true\n        elseif orientation == \"bottom\" then\n            vim.cmd(\"topleft split\")\n            return true\n        end\n    end\n    return false\nend\n\n-- jump_tab will open a new tab then jump to the symbol\n--\n-- @param location (table) A location object as defined by\n-- the LSP.\n-- @param node (table) An element which is being jumped to,\n-- if this element has a high level \"references\" field with\n-- more \"Location\" objects, they will be highlighted as well.\nfunction M.jump_tab(location, node, offset_encoding)\n    M.set_jump_hl(false, nil)\n    vim.cmd(\"tabedit \" .. location.uri)\n    vim.cmd(\"set nocursorline\")\n    -- if the panel currently has a component \"popped-out\"\n    -- close it before jumping.\n    lib_panel.close_current_popout()\n    vim.lsp.util.jump_to_location(location, offset_encoding or \"utf-8\")\n    M.set_jump_hl(true, node)\nend\n\n-- jump_split will open a new split then jump to the symbol\n--\n-- @param split (string) The type of split, valid arguments\n-- are \"split\" or \"vsplit\".\n-- @param location (table) A location object as defined by\n-- the LSP.\n-- @param node (table) An element which is being jumped to,\n-- if this element has a high level \"references\" field with\n-- more \"Location\" objects, they will be highlighted as well.\nfunction M.jump_split(split, location, node, offset_encoding)\n    M.set_jump_hl(false, nil)\n    if not move_or_create(config[\"panel\"].orientation) then\n        vim.cmd(split)\n    end\n    -- if the panel currently has a component \"popped-out\"\n    -- close it before jumping.\n    lib_panel.close_current_popout()\n    vim.lsp.util.jump_to_location(location, offset_encoding or \"utf-8\")\n    M.set_jump_hl(true, node)\nend\n\n-- jump_neighbor will jump to the symbol using the\n-- closest left or right window.\n--\n-- a window will be created if it does not exist.\n--\n-- @param location (table) A location object as defined by\n-- the LSP.\n-- @param node (table) An element which is being jumped to,\n-- if this element has a high level \"references\" field with\n-- more \"Location\" objects, they will be highlighted as well.\nfunction M.jump_neighbor(location, node, offset_encoding)\n    M.set_jump_hl(false, nil)\n    move_or_create(config[\"panel\"].orientation)\n    -- if the panel currently has a component \"popped-out\"\n    -- close it before jumping.\n    lib_panel.close_current_popout()\n    vim.lsp.util.jump_to_location(location, offset_encoding or \"utf-8\")\n    M.set_jump_hl(true, node)\n\n    -- cleanup any [No Name] buffers if they exist\n    for _, buf in ipairs(vim.api.nvim_list_bufs()) do\n        local name = vim.api.nvim_buf_get_name(buf)\n        if name == \"\" then\n            vim.api.nvim_buf_delete(buf, {force=true})\n        end\n    end\nend\n\n-- jump_invoking will jump to the symbol using the\n-- window that initially invoked the calltree.\n--\n-- a window is created and seen as the new invoking window\n-- if the original invoking window has been closed.\n--\n-- @param location (table) A location object as defined by\n-- the LSP.\n-- @param win (int) A window handle of the invoking window\n-- to jump to.\n-- @param node (table) An element which is being jumped to,\n-- if this element has a high level \"references\" field with\n-- more \"Location\" objects, they will be highlighted as well.\nfunction M.jump_invoking(location, win, node, offset_encoding)\n    M.set_jump_hl(false, nil)\n    if not vim.api.nvim_win_is_valid(win) then\n        if config[\"panel\"].orientation == \"left\" then\n            vim.cmd(\"botright vsplit\")\n        elseif config[\"panel\"].orientation == \"right\" then\n            vim.cmd(\"topleft vsplit\")\n        elseif config[\"panel\"].orientation == \"top\" then\n            vim.cmd(\"topleft split\")\n        elseif config[\"panel\"].orientation == \"bottom\" then\n            vim.cmd(\"topleft split\")\n        end\n        win = vim.api.nvim_get_current_win()\n    end\n    vim.api.nvim_set_current_win(win)\n\n    -- if the panel currently has a component \"popped-out\"\n    -- close it before jumping.\n    lib_panel.close_current_popout()\n    vim.lsp.util.jump_to_location(location, offset_encoding or \"utf-8\")\n    M.set_jump_hl(true, node)\n\n    -- cleanup any [No Name] buffers if they exist\n    for _, buf in ipairs(vim.api.nvim_list_bufs()) do\n        local name = vim.api.nvim_buf_get_name(buf)\n        if name == \"\" then\n            vim.api.nvim_buf_delete(buf, {force=true})\n        end\n    end\n\n    return win\nend\n\n-- set_jump_hl will highlight the symbol and\n-- any references to the symbol if set == true.\n--\n-- @param set (bool) If false highlights any previously created\n-- jump highlights will be removed.\n--\n-- @param node (table) An element which is being jumped to,\n-- the node must have a high level \".location\" field.\n-- if this element has a high level \".references\" field with\n-- an array of \"Range\" objects (specified by LSP),\n-- they will be highlighted as well.\nfunction M.set_jump_hl(set, node)\n    if not set then\n        if\n            M.last_highlighted_buffer ~= nil\n            and vim.api.nvim_buf_is_valid(M.last_highlighted_buffer)\n        then\n            vim.api.nvim_buf_clear_namespace(\n                M.last_highlighted_buffer,\n                M.jump_higlight_ns,\n                0,\n                -1\n            )\n        end\n        return\n    end\n\n    M.last_highlighted_buffer = vim.api.nvim_get_current_buf()\n\n    -- set highlght for function itself\n    local location = node.location\n    if location == nil then\n        return\n    end\n    local range = location.range\n\n    vim.api.nvim_buf_add_highlight(\n        M.last_highlighted_buffer,\n        M.jump_higlight_ns,\n        lib_hi.hls.SymbolJumpHL,\n        range[\"start\"].line,\n        range[\"start\"].character,\n        range[\"end\"].character\n    )\n    -- apply it to all the references\n    if node.references ~= nil then\n        for _, ref in ipairs(node.references) do\n            vim.api.nvim_buf_add_highlight(\n                M.last_highlighted_buffer,\n                M.jump_higlight_ns,\n                lib_hi.hls.SymbolJumpRefsHL,\n                ref[\"start\"].line,\n                ref[\"start\"].character,\n                ref[\"end\"].character\n            )\n        end\n    end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/lsp/hover.lua",
    "content": "local M = {}\n\nlocal float_win = nil\n\n-- close_hover_popups closes the created popup window\n-- if it exists.\nfunction M.close_hover_popup()\n    if float_win ~= nil and\n        vim.api.nvim_win_is_valid(float_win) then\n        vim.api.nvim_win_close(float_win, true)\n        float_win = nil\n    end\nend\n\n-- hover_handle shows hover information for a symbol in a calltree\n-- ui window.\n--\n-- modified from neovim runtime/lua/vim/lsp/handlers.lua\n-- function conforms to client LSP handler signature.\nfunction M.hover_handler(_, result, ctx, config)\n    M.close_hover_popup()\n    -- get lines from result\n    config = config or {}\n    config.focus_id = ctx.method\n    if not (result and result.contents) then\n      -- return { 'No information available' }\n      return\n    end\n    local lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents)\n    lines = vim.lsp.util.trim_empty_lines(lines)\n    if vim.tbl_isempty(lines) then\n      -- return { 'No information available' }\n      return\n    end\n\n    -- create buffer for popup\n    local buf = vim.api.nvim_create_buf(false, false)\n    if buf == 0 then\n        vim.api.nvim_err_writeln(\"details_popup: could not create details buffer\")\n        return\n    end\n    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'delete')\n    vim.api.nvim_buf_set_option(buf, 'syntax',    'markdown')\n    vim.api.nvim_buf_set_option(buf, 'filetype',  'markdown')\n\n    lines = vim.lsp.util.stylize_markdown(buf, lines, {})\n\n    local width = 20\n    for _, line in ipairs(lines) do\n        local line_width = vim.fn.strdisplaywidth(line)\n        if line_width > width then\n            width = line_width\n        end\n    end\n\n    vim.api.nvim_buf_set_option(buf, 'modifiable', true)\n    vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)\n    vim.api.nvim_buf_set_option(buf, 'modifiable', false)\n    local popup_conf = vim.lsp.util.make_floating_popup_options(\n            width,\n            #lines,\n            {\n                border= \"rounded\",\n                focusable= false,\n                zindex = 99,\n            }\n    )\n    float_win = vim.api.nvim_open_win(buf, false, popup_conf)\n\n  return float_win\nend\n\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/lsp/init.lua",
    "content": "local lib_notify = require('litee.lib.notify')\nlocal lib_tree_node = require('litee.lib.tree.node')\n\nlocal M = {}\n\n-- multi_client_request makes an LSP request to multiple clients.\n--\n-- the signature is the same as an individual LSP client request method\n-- but takes a list of clients as the first argument.\nfunction M.multi_client_request(clients, method, params, handler, bufnr)\n    for _, client in ipairs(clients) do\n        if client.supports_method(method) then\n            client.request(method, params, handler, bufnr or 0)\n            return client\n        end\n    end\nend\n\n-- gather_sybmbols_async_handler is the async handler\n-- for gather_symbols_async method and incrementally\n-- builds a tree of symbols from a workspace symbols\n-- request.\nfunction M.gather_symbols_async_handler(node, co)\n    return function(err, result, _, _)\n        if err ~= nil then\n            coroutine.resume(co, nil)\n            return\n        end\n        if result == nil then\n            coroutine.resume(co, nil)\n            return\n        end\n\n        local start_line, uri = \"\", \"\"\n        if node.call_hierarchy_item ~= nil then\n            start_line = node.call_hierarchy_item.range.start.line\n            uri = node.call_hierarchy_item.uri\n        elseif node.document_symbol ~= nil then\n            start_line = node.document_symbol.range.start.line\n            uri = node.uri\n        end\n\n        for _, res in ipairs(result) do\n            if\n                res.location.uri == uri and\n                res.location.range.start.line ==\n                start_line\n            then\n                coroutine.resume(co, res)\n                return\n            end\n        end\n        coroutine.resume(co, nil)\n    end\nend\n\n-- gather_symbols_async will acquire a list of workspace symbols given\n-- a tree of call_hierarchy items.\nfunction M.gather_symbols_async(root, children, component_state, callback)\n    local co = nil\n    local all_nodes = {}\n    table.insert(all_nodes, root)\n    for _, child in ipairs(children) do\n        table.insert(all_nodes, child)\n    end\n    co = coroutine.create(function()\n        for i, node in ipairs(all_nodes) do\n            local params = {\n                query = node.name,\n            }\n            lib_notify.notify_popup(\"gathering symbols [\" .. i .. \"/\" .. #all_nodes .. \"]\", \"warning\")\n            local client = M.multi_client_request(\n                component_state.active_lsp_clients,\n                \"workspace/symbol\",\n                params,\n                -- handler will call resume for this co.\n                M.gather_symbols_async_handler(node, co)\n            )\n            if client.offset_encoding ~= nil then\n                node.offset_encoding = client.offset_encoding\n            end\n            node.symbol = coroutine.yield()\n            lib_notify.close_notify_popup()\n        end\n        callback()\n    end)\n    coroutine.resume(co)\nend\n\n-- symbol_from_node attempts to extract the workspace\n-- symbol the node represents.\n--\n-- @param clients (table) All active lsp clients\n-- @param node (table) A node with a \"call_hierarhcy_item\"\n-- field we are acquiring workspace symbols for.\n-- @param bufnr (int) An window handle to the buffer\n-- containing the node.\n-- @returns (table) the SymbolInformation LSP structure, see:\n-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#symbolInformation\nfunction M.symbol_from_node(clients, node, bufnr)\n    local params = {\n        query = node.name,\n    }\n    for _, client in ipairs(clients) do\n        if not client.supports_method(\"workspace/symbol\") then\n            goto continue\n        end\n        -- not all LSPs are optimized, specially ones in early development, set\n        -- this timeout high.\n        local out = client.request_sync(\"workspace/symbol\", params, 5000, bufnr)\n        if out == nil then\n            goto continue\n        end\n        if out.err ~= nil or (out.result == nil or #out.result <= 0) then\n            goto continue\n        end\n        for _, res in ipairs(out.result) do\n            if\n                res.uri == node.uri and\n                res.location.range.start.line ==\n                node.call_hierarchy_item.range.start.line\n            then\n                return res\n            end\n        end\n        ::continue::\n    end\n    return nil\nend\n\n-- conv_symbolinfo_to_docsymbol will convert a SymbolInformation\n-- model to a DocumentSymbol mode.\n--\n-- this is handy when working with documentSymbol requests and\n-- users do not want to handle two data models in their code.\n--\n-- @param symbolinfo (table) A SymbolInformation structure as\n-- defined by the LSP specification.\n-- @returns (table) A DocumentSymbol structure as defined by\n-- the LSP specification.\nfunction M.conv_symbolinfo_to_docsymbol(symbolinfo)\n    local document_symbol = {}\n\n    -- these are mandatory fields per the LSP spec,\n    -- return nil if they arent there.\n    if\n        symbolinfo.name == nil or\n        symbolinfo.kind == nil or\n        symbolinfo.location == nil or\n        symbolinfo.location.range == nil\n    then\n        return nil\n    end\n\n    document_symbol.name    = symbolinfo.name\n    document_symbol.kind    = symbolinfo.kind\n    document_symbol.range   = symbolinfo.location.range\n    document_symbol.children = {}\n    document_symbol.details = \"\"\n    document_symbol.tags = {}\n    document_symbol.deprecated = false\n    document_symbol.selectionRange = symbolinfo.location.range\n    return document_symbol\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/lsp/wrappers.lua",
    "content": "local lib_notify = require('litee.lib.notify')\nlocal M = {}\n\nfunction M.buf_document_symbol()\n    lib_notify.notify_popup_with_timeout(\"Creating document outline...\", 7500, \"info\")\n    vim.lsp.buf.document_symbol()\nend\n\nfunction M.buf_incoming_calls()\n    lib_notify.notify_popup_with_timeout(\"Creating incoming calls outline...\", 7500, \"info\")\n    vim.lsp.buf.incoming_calls()\nend\n\nfunction M.buf_outgoing_calls()\n    lib_notify.notify_popup_with_timeout(\"Creating outgoing calls outline...\", 7500, \"info\")\n    vim.lsp.buf.outgoing_calls()\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/navi/init.lua",
    "content": "local M = {}\n\n-- next moves the cursor in the window of the provided\n-- component_state forward\n--\n-- @param component_state (table) A state table as defined\n-- in lib/state.\n-- @param pre_cb function() A callback which fires just before\n-- the cursor move.\n-- @param post_cb function() A callback which fires just after\n-- the cursor move.\nfunction M.next(component_state, pre_cb, post_cb)\n    if component_state.win == nil\n        or not vim.api.nvim_win_is_valid(component_state.win) then\n        return\n    end\n    local cur_cursor = vim.api.nvim_win_get_cursor(component_state.win)\n    local lines_nr = vim.api.nvim_buf_line_count(component_state.buf)\n    if cur_cursor[1] + 1 > lines_nr then\n        return\n    end\n    cur_cursor[1] = cur_cursor[1] + 1\n    if pre_cb ~= nil then pre_cb() end\n    vim.api.nvim_win_set_cursor(component_state.win, cur_cursor)\n    if post_cb ~= nil then pre_cb() end\nend\n\n-- next moves the cursor in the window of the provided\n-- component_state backwards\n--\n-- @param component_state (table) A state table as defined\n-- in lib/state.\n-- @param pre_cb function() A callback which fires just before\n-- the cursor move.\n-- @param post_cb function() A callback which fires just after\n-- the cursor move.\nfunction M.previous(component_state, pre_cb, post_cb)\n    if component_state.win == nil\n        or not vim.api.nvim_win_is_valid(component_state.win) then\n        return\n    end\n    local cur_cursor = vim.api.nvim_win_get_cursor(component_state.win)\n    if cur_cursor[1] - 1 < 1 then\n        return\n    end\n    cur_cursor[1] = cur_cursor[1] - 1\n    if pre_cb ~= nil then pre_cb() end\n    vim.api.nvim_win_set_cursor(component_state.win, cur_cursor)\n    if post_cb ~= nil then pre_cb() end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/notify/init.lua",
    "content": "local notify_config = require('litee.lib.config').config[\"notify\"]\nlocal M = {}\n\nlocal float_wins = {}\n\nfunction M.close_notify_popup()\n    if not notify_config.enabled then\n        return\n    end\n    if float_wins == nil then\n        return\n    end\n    for _, float_win in ipairs(float_wins) do\n        if vim.api.nvim_win_is_valid(float_win) then\n            vim.api.nvim_win_close(float_win, true)\n        end\n    end\n    float_wins = nil\nend\n\nfunction M.notify_popup_with_timeout(text, ms, sev)\n    if not notify_config.enabled then\n        return\n    end\n    M.notify_popup(text, sev)\n    local timer = vim.loop.new_timer()\n    timer:start(ms, 0, vim.schedule_wrap(\n        M.close_notify_popup\n    ))\nend\n\nfunction M.notify_popup(text, sev)\n    if not notify_config.enabled then\n        return\n    end\n\n    if float_wins == nil then\n        float_wins = {}\n    end\n\n    local buf = vim.api.nvim_create_buf(false, true)\n    if buf == 0 then\n        vim.api.nvim_err_writeln(\"details_popup: could not create details buffer\")\n        return\n    end\n    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'delete')\n    vim.api.nvim_buf_set_option(buf, 'syntax', 'yaml')\n\n    local lines = {text}\n    local width = 20\n    local line_width = vim.fn.strdisplaywidth(text)\n    if line_width > width then\n        width = line_width\n    end\n\n    vim.api.nvim_buf_set_option(buf, 'modifiable', true)\n    vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)\n    vim.api.nvim_buf_set_option(buf, 'modifiable', false)\n    local popup_conf = {\n        relative = \"editor\",\n        anchor = \"SE\",\n        width = width,\n        height = 1,\n        focusable = false,\n        zindex = 99,\n        style = \"minimal\",\n        border = \"rounded\",\n        row = 0,\n        col = vim.opt.columns:get(),\n    }\n    local float_win = vim.api.nvim_open_win(buf, false, popup_conf)\n    table.insert(float_wins, float_win)\n    if sev == \"error\" then\n        vim.api.nvim_win_set_option(float_win, 'winhl', \"Normal:Error\")\n    elseif sev == \"warning\" then\n        vim.api.nvim_win_set_option(float_win, 'winhl', \"Normal:WarningMsg\")\n    else\n        vim.api.nvim_win_set_option(float_win, 'winhl', \"Normal:NormalFloat\")\n    end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/panel/autocmds.lua",
    "content": "local lib_state = require('litee.lib.state')\nlocal lib_panel = require('litee.lib.panel')\n\nlocal M = {}\n\nfunction M.on_resize()\n    local cur_win = vim.api.nvim_get_current_win()\n    local cur_tab = vim.api.nvim_get_current_tabpage()\n    local state = lib_state.get_state(cur_tab)\n    if state == nil then\n        return\n    end\n    local is_open = lib_panel.is_panel_open(state)\n    if is_open then\n        lib_panel.toggle_panel(state, false, true)\n        vim.api.nvim_set_current_win(cur_win)\n    end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/panel/init.lua",
    "content": "local lib_state = require('litee.lib.state')\nlocal config = require('litee.lib.config').config\nlocal lib_notify = require('litee.lib.notify')\nlocal lib_util = require('litee.lib.util')\nlocal lib_util_win = require('litee.lib.util.window')\n\nlocal M = {}\n\n-- components maps a unique component map\n-- with a set of callbacks (see M.register_component)\n--\n-- the order in which components exist in this map\n-- determines the component's order in the panel.\nlocal components = {}\n\n-- register_component adds a component to\n-- the panel.\n--\n-- the panel's layout is determined by the\n-- order in which components are registered.\n--\n-- registering a component *must* include a \"pre_window_create\"\n-- callback and can optionally provide a \"post_window_create\"\n-- callback.\n--\n-- @param component (string) Unique name for a component,\n-- subsequent calls for a unique component will over write\n-- previous\n-- @param pre_window_create (function(state)) A callback which must\n-- prepare the provided state object, as defined by lib/state.lua\n-- with a valid buffer. The callback is free to perform any other\n-- tasks such as writing to the buffer if desired. The buffer\n-- ID should be stored in the component's \"buf\" field in state\n-- and will be displayed in the appropriate panel's window on\n-- toggle. This callback can return false when the window should\n-- not be opened in the panel and true to indicate it should.\n-- @param post_window_create (function(state)) A callback which can customize\n-- the component window further after being displayed in the panel. Useful for\n-- setting up component-specific window options and winhl configurations.\n-- The state[component].win field will be populated with the window id of the\n-- panel window for further configuration.\nfunction M.register_component(component, pre_window_create, post_window_create)\n    components[component] = {\n        pre = pre_window_create,\n        post = post_window_create\n    }\nend\n\nfunction M.is_panel_open(state)\n    local component_open = false\n    for component, _ in pairs(components) do\n        if\n            state[component] ~= nil\n            and state[component].win ~= nil\n            and vim.api.nvim_win_is_valid(state[component].win)\n        then\n            component_open = true\n        end\n    end\n    return component_open\nend\n\n-- toggle_panel will toggle the panel open and\n-- close in the common case. Arguments can be\n-- used to alter how the toggle takes place.\n--\n-- @param state (table) The full state table as defined\n-- in lib/state.lua\n-- @param keep_open (bool) If the panel is currently open\n-- perform a no-op, useful when the caller only wants to\n-- confirm the panel is present.\n-- @param cycle (bool) Close and open the panel in succession,\n-- useful when resizing events occur to snap the panel back\n-- into the appropriate size.\nfunction M.toggle_panel(state, keep_open, cycle, close)\n    local cur_win = vim.api.nvim_get_current_win()\n    -- if state is nil then try to grab it from current tab.\n    if state == nil then\n        local cur_tab = vim.api.nvim_get_current_tabpage()\n        state = lib_state.get_state(cur_tab)\n        if state == nil then\n            lib_notify.notify_popup_with_timeout(\"Must open a litee component before toggling the panel.\", 1750, \"error\")\n            return\n        end\n    end\n    local component_open = false\n    local component_cursors = {}\n    for component, _ in pairs(components) do\n        if\n            state[component] ~= nil\n            and state[component].win ~= nil\n            and vim.api.nvim_win_is_valid(state[component].win)\n        then\n            component_open = true\n            component_cursors[component] = vim.api.nvim_win_get_cursor(state[component].win)\n        end\n    end\n\n    -- components are open, close them, recording its dimensions\n    -- for proper restore.\n    if\n        not keep_open or\n        cycle or\n        close\n    then\n        if component_open then\n            for component, _ in pairs(components) do\n                if\n                    state[component] ~= nil\n                    and state[component].win ~= nil\n                    and vim.api.nvim_win_is_valid(state[component].win)\n                then\n                    state[component].win_dimensions = {\n                        height = vim.api.nvim_win_get_height(state[component].win),\n                        width = vim.api.nvim_win_get_width(state[component].win)\n                    }\n                    vim.api.nvim_win_close(state[component].win, true)\n                end\n            end\n            if cycle then\n                M.toggle_panel(state, false, false)\n            end\n            return\n        end\n    end\n\n    for component, callbacks in pairs(components) do\n        if state[component] ~= nil then\n            if callbacks.pre(state) then\n                M._open_window(component, state)\n                -- restore cursor positions if possible.\n                if component_cursors[component] ~= nil then\n                    lib_util.safe_cursor_reset(\n                        state[component].win,\n                        component_cursors[component]\n                    )\n                end\n            end\n        end\n    end\n    vim.api.nvim_set_current_win(cur_win)\nend\n\n-- Similar to toggle_panel but retrieves state from\n-- Neovim's current context.\nfunction M.toggle_panel_ctx(keep_open, cycle)\n    local state = lib_state.get_state_ctx()\n    if state == nil then\n        return\n    end\n    M.toggle_panel(state, keep_open, cycle)\nend\n\n-- realize_current_and_desired will determine the current and desired layouts\n-- given a requested window type to open.\n--\n-- @param check_component (string) The identifier of a registered component\n-- which is checked against the current layout.\n-- @param desired_compoent The identifier of a registered component which is\n-- the desired component to add/display in the panel.\n-- @param current_layout (list of int) A list of window ids currently comprising\n-- any open panel components.\n-- @param desired_layout (list of string) A list of panel components desired to be\n-- displayed.\n-- @param state (table) A table of state as defined by lib/state.lua\n--\n-- @returns continue (bool) A bool which informs the caller to stop processing\n-- the declarative evaluation of the panel layout. This occurs if the desired\n-- component is already being displayed.\nlocal function realize_current_and_desired(check_component, desired_component, current_layout, desired_layout, state)\n    local current_tabpage = vim.api.nvim_win_get_tabpage(\n        vim.api.nvim_get_current_win()\n    )\n\n    -- check if the desired window exists.\n    if\n        state[check_component] == nil or\n        state[check_component].win == nil or\n        (not vim.api.nvim_win_is_valid(state[check_component].win))\n    then\n        if check_component == desired_component then\n            -- checked window is invalid, its also the desired window to open\n            -- add it to desired layout.\n            table.insert(desired_layout, desired_component)\n        end\n        return true\n    end\n    local win = state[check_component].win\n\n    local win_tabpage = vim.api.nvim_win_get_tabpage(win)\n    -- desired window type is already open on current tabpage, noop\n    if check_component == desired_component and current_tabpage == win_tabpage then\n        return false\n    end\n    -- the checked window type is open and on the current tab, unconditionally add it to\n    -- desired_layout to preserve it existence.\n    if current_tabpage == win_tabpage then\n        table.insert(current_layout, win)\n        table.insert(desired_layout, check_component)\n    -- the window type we are checking is also the desired window type, but its\n    -- opened in another tab, close it and add desired window type to desired layout.\n    -- it will be opened on the current tab.\n    elseif check_component == desired_component then\n        vim.api.nvim_win_close(win, true)\n        table.insert(desired_layout, desired_component)\n    end\n    return true\nend\n\n-- open_window will first compute the current UI layout\n-- then compute the desired layout and finally call\n-- _setup_window with both.\n--\n-- @param desired_component (string) The registered component\n-- which should be opened in the panel.\n--\n-- @param state (table) The state table as defined by\n-- lib/state.lua\nfunction M._open_window(desired_component, state)\n    -- holds open window handles we'll reuse\n    local current_layout = {}\n    -- holds the window types to ensure present in the ui\n    local desired_layout = {}\n\n    for check_component, _ in pairs(components) do\n        if not realize_current_and_desired(check_component, desired_component, current_layout, desired_layout, state) then\n            return\n        end\n    end\n\n    M._setup_window(current_layout, desired_layout, state)\nend\n\n-- open_to opens the panel and moves the cursor to the requested\n-- component.\n--\n-- if open_to is called when nvim is focused inside\n-- the component the focus will be switched back to the window the ui\n-- was invoked from.\n--\n-- @param component (string) The component to open to.\n-- @param state (table) The state table as defined by\n-- lib/state.lua\n-- @return opened (bool) Whether the panel has been open.\nfunction M.open_to(component, state)\n    if state[component] == nil then\n        -- notify.notify_popup_with_timeout(\"Cannot toggle panel until ..\", 1750, \"error\")\n        return false\n    end\n    local current_win = vim.api.nvim_get_current_win()\n    if  current_win == state[component].win then\n        vim.api.nvim_set_current_win(state[component].invoking_win)\n        return\n    end\n    if\n        state[component].win ~= nil\n        and vim.api.nvim_win_is_valid(state[component].win)\n    then\n        vim.api.nvim_set_current_win(state[component].win)\n        return\n    end\n    M.toggle_panel(state, true, false)\n    vim.api.nvim_set_current_win(state[component].win)\nend\n\nM.popout_panel_state = nil\n\nfunction M.close_current_popout()\n    if M.popout_panel_state == nil then\n        return\n    end\n    if vim.api.nvim_win_is_valid(M.popout_panel_state.float_win) then\n        vim.api.nvim_win_close(M.popout_panel_state.float_win, true)\n        -- if panel was closed when popout panel was created, close it again,\n        -- otherwise open it again.\n        if M.popout_panel_state.panel_open then\n            -- issue a cycle here to reset any odd spacing from removing the window\n            -- from the panel.\n            M.toggle_panel(M.popout_panel_state.litee_state, false, true, false)\n        end\n    end\n    M.popout_panel_state = nil\nend\n\n-- popout_to will pop the requested component\n-- out of the panel to a popup on the bottom right\n-- hand of the editor and focus the popup window.\n--\n-- if the panel is open when a call to \"popout_to\" is made,\n-- when the popup is closed via \"close_current_popout()\",\n-- or a jump is made with lib/jump functions,\n-- then the window will be popped back into the panel.\n--\n-- if the panel was closed when a call to \"popup_to\" was made\n-- this is remembered, and the panel will remain closed after\n-- \"close_current_popup()\" is called or a jump is made with\n-- lib/jump functions.\n--\n-- @param component (string) The registered component name\n-- to create the popout for.\n-- @param state (table) The current global state as defined\n-- in lib/state\n-- @param before_focus A callback ran just before switching\n-- focus to the popout floating win. This callback is ran\n-- in the original win when the call to popout_to was made.\n-- @param after_focus Same as \"before_focus\" but runs inside\n-- the newly created popout floating win.\nfunction M.popout_to(component, state, before_focus, after_focus)\n    if\n        state == nil\n        or state[component] == nil\n        or components[component] == nil\n    then\n        return\n    end\n\n    -- close any popup which maybe open.\n    M.close_current_popout()\n\n    -- reset the popout panel state\n    M.popout_panel_state = {}\n\n    -- check panel open state so we can restore it correctly\n    -- on close_current_popout()\n    M.popout_panel_state.panel_open = M.is_panel_open(state)\n\n    local popup_conf = {\n        relative = \"editor\",\n        anchor = \"NW\",\n        width = math.floor(vim.opt.columns:get()/2),\n        height = math.floor(vim.opt.lines:get()/2),\n        focusable = true,\n        zindex = 98,\n        border = \"rounded\",\n        row = math.floor(vim.opt.lines:get() - (vim.opt.cmdheight:get() + 1)/2),\n        col = math.floor(vim.opt.columns:get()/2),\n    }\n\n    if  M.popout_panel_state.panel_open\n        and state[component].win ~= nil\n        and vim.api.nvim_win_is_valid(state[component].win)\n    then\n        -- if panel is open and win is valid make it a float.\n        vim.api.nvim_win_set_config(state[component].win, popup_conf)\n        M.popout_panel_state.float_win = state[component].win\n        M.popout_panel_state.litee_state = state\n    else\n        -- if the panel is closed or win is not valid\n        -- manually create the floating window.\n        components[component].pre(state)\n        M.popout_panel_state.float_win = vim.api.nvim_open_win(state[component].buf, false, popup_conf)\n        state[component].win = M.popout_panel_state.float_win\n        M._set_win_opts(M.popout_panel_state.float_win)\n        M.popout_panel_state.litee_state = state\n        vim.api.nvim_win_set_buf(M.popout_panel_state.float_win, state[component].buf)\n    end\n\n    -- run callback before focusing the callback window\n    if before_focus ~= nil then\n        before_focus(true)\n    end\n\n    -- set focus into float\n    vim.api.nvim_set_current_win(M.popout_panel_state.float_win)\n\n    -- if we created a floating win, we need to run post callbacks\n    -- when inside of it.\n    components[component].post(state)\n\n    -- run callback after focusing the callback window\n    if after_focus ~= nil then\n        after_focus()\n    end\nend\n\n-- setup_window evaluates the current layout and the desired layout\n-- and opens the necessary windows to obtain the desired layout.\n--\n-- @param current_layout (list of int) A list of win handles comprising\n-- the currently opened panel windows. If present, they will be reused\n-- to realize the desired_layout.\n-- @param desired_layout (list of string) A list of components desired\n-- to be opened and present in the panel.\n-- @param state (table) The state table as defined by\n-- lib/state.lua\nfunction M._setup_window(current_layout, desired_layout, state)\n    for i, component in ipairs(desired_layout) do\n        local buffer_to_set = nil\n        local dimensions_to_set = nil\n\n        buffer_to_set = state[component].buf\n        if state[component].win_dimensions ~= nil then\n            dimensions_to_set = state[component].win_dimensions\n        end\n\n        -- we can reuse the current layout windows\n        if i <= #current_layout then\n            vim.api.nvim_win_set_buf(current_layout[i], buffer_to_set)\n            state[component].win = current_layout[i]\n            vim.api.nvim_set_current_win(state[component].win)\n            goto continue\n        end\n\n        -- we are out of open windows, so we need to create some\n\n        if #current_layout == 0 then\n            -- there is no current layout, so just do a botright or equivalent\n            if config[\"panel\"].orientation == \"left\" then\n                vim.cmd(\"topleft vsplit\")\n                vim.cmd(\"vertical resize \" ..\n                            config[\"panel\"].panel_size)\n            elseif config[\"panel\"].orientation == \"right\" then\n                vim.cmd(\"botright vsplit\")\n                vim.cmd(\"vertical resize \" ..\n                            config[\"panel\"].panel_size)\n            elseif config[\"panel\"].orientation == \"top\" then\n                vim.cmd(\"topleft split\")\n                vim.cmd(\"resize \" ..\n                            config[\"panel\"].panel_size)\n            elseif config[\"panel\"].orientation == \"bottom\" then\n                vim.cmd(\"botright split\")\n                vim.cmd(\"resize \" ..\n                            config[\"panel\"].panel_size)\n            end\n            goto set\n        end\n\n        -- cursor currently in a reused window, split according to layout config\n        if config[\"panel\"].orientation == \"left\" then\n            vim.cmd(\"below split\")\n        elseif config[\"panel\"].orientation == \"right\" then\n            vim.cmd(\"below split\")\n        elseif config[\"panel\"].orientation == \"top\" then\n            vim.cmd(\"vsplit\")\n        elseif config[\"panel\"].orientation == \"bottom\" then\n            vim.cmd(\"vsplit\")\n        end\n\n        ::set::\n        cur_win = vim.api.nvim_get_current_win()\n        state[component].win = cur_win\n        vim.api.nvim_win_set_buf(state[component].win, buffer_to_set)\n        M._set_win_opts(state[component].win)\n        if\n            dimensions_to_set ~= nil and\n            dimensions_to_set.width ~= nil and\n            dimensions_to_set.height ~= nil\n        then\n            if (config[\"panel\"].orientation == \"left\" or config[\"panel\"].orientation == \"right\") then\n                vim.api.nvim_win_set_width(cur_win, dimensions_to_set.width)\n            else\n                vim.api.nvim_win_set_height(cur_win, dimensions_to_set.height)\n            end\n        else\n            dimensions_to_set = {}\n            dimensions_to_set.height = vim.api.nvim_win_get_height(cur_win)\n            dimensions_to_set.wdith  = vim.api.nvim_win_get_width(cur_win)\n            state[component].dimensions = dimensions_to_set\n        end\n\n        ::continue::\n        if components[component].post ~= nil then\n            components[component].post(state)\n        end\n    end\nend\n\n-- _set_win_opts sets the manditory window options for a\n-- panel window.\n-- @param win (int) Window ID of panel window\nfunction M._set_win_opts(win)\n    vim.api.nvim_win_set_option(win, 'number', false)\n    vim.api.nvim_win_set_option(win, 'cursorline', true)\n    vim.api.nvim_win_set_option(win, 'relativenumber', false)\n    vim.api.nvim_win_set_option(win, 'signcolumn', 'no')\n    vim.api.nvim_win_set_option(win, 'wrap', false)\n    vim.api.nvim_win_set_option(win, 'winfixwidth', true)\n    vim.api.nvim_win_set_option(win, 'winfixheight', true)\n    vim.api.nvim_win_set_option(win, 'winhighlight', 'Normal:NormalSB')\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/state/autocmds.lua",
    "content": "local lib_tree  = require('litee.lib.tree')\nlocal lib_state = require('litee.lib.state')\n\nlocal M = {}\n\nM.on_tab_closed = function(tab)\n    local state = lib_state.get_state(tab)\n    if state == nil then\n        return\n    end\n    for _, s in pairs(state) do\n        if s ~= nil then\n            lib_tree.remove_tree(s.tree)\n        end\n    end\n    lib_state.put_state(tab, nil)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/state/init.lua",
    "content": "local M = {}\n\n-- registry is a per-tab-page registry for\n-- state.\n--\n-- state defines information necessary for\n-- a UI component to be used with litee-lib.\n--\n-- the state structure is as follows:\n-- \"component\" = {\n--     buf = 0,\n--     win = 0,\n--     tab = 0,\n--     tree = 0,\n--     win_dimensions = {0, 0},\n--     invoking_win = 0,\n--     active_lsp_clients = {list of lsp clients},\n--     (component specific fields)...\n-- }\n--\n-- a component using the registry should consider\n-- only it's portion of the state as writable but\n-- is free to pass the full state object to other\n-- lib methods.\nM.registry = {}\n\n-- get_state returns the state for the given tab\n-- @param tab (int) The tab ID to retrieve state for.\n-- @returns state (table) The state as defined by this\n-- module.\nfunction M.get_state(tab)\n    return M.registry[tab]\nend\n\n-- get_state_ctx is similiar to get_state but obtains\n-- the tab ID from the current Neovim context.\nfunction M.get_state_ctx()\n    local win    = vim.api.nvim_get_current_win()\n    local tab    = vim.api.nvim_win_get_tabpage(win)\n    local state = M.registry[tab]\n    return state\nend\n\n-- get_component_state returns the state for a\n-- particular component that's utilizing lib state.\n--\n-- @param tab (int) The tab ID to retrieve state for.\n-- @param component (string) The name of the component\n-- storing its state.\nfunction M.get_component_state(tab, component)\n    local s = M.registry[tab]\n    if s == nil then return nil end\n    return s[component]\nend\n\n-- put_state writes a state table to the registry for\n-- later retrieval.\n--\n-- this method overwrites all current state so use with\n-- caution.\n-- @param tab (int) The tab ID to associate the provided state\n-- with\n-- @param state (table) The state as defined by this\n-- module.\n-- @returns state (table) The updated state table as defined\n-- by this module\nfunction M.put_state(tab, state)\n    M.registry[tab] = state\n    return M.registry[tab]\nend\n\n\n-- put_component_state will store the component state for\n-- later retrieval.\n--\n-- @param tab (int) The tab ID to associate the provided state\n-- with\n-- @param component (string) The name of the component\n-- storing its state table.\n-- @param state (table) The state as defined by this\n-- module. This table should not include the component\n-- name as a leading key.\n-- @returns state (table) The updated state table as defined\n-- by this module\nfunction M.put_component_state(tab, component, state)\n    local s = M.registry[tab]\n    if s == nil then\n        s = {}\n        M.registry[tab] = s\n    end\n    s[component] = state\n    return s\nend\n\nfunction M.get_active_components(tab)\n    local s = M.registry[tab]\n    local components = {}\n    for component, _ in pairs(s) do\n        table.insert(components, component)\n    end\n    return components\nend\n\nfunction M.get_type_from_buf(tab, buf)\n    local state = M.registry[tab]\n    if state == nil then\n        return nil\n    end\n    for component, s in pairs(state) do\n        if buf == s.buf then\n            return component\n        end\n    end\n    return nil\nend\n\nM.get_tree_from_buf = function(tab, buf)\n    local state = M.registry[tab]\n    if state == nil then\n        return nil\n    end\n    local type = M.get_type_from_buf(tab, buf)\n    if type == nil then\n        return nil\n    end\n    return state[type].tree\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/term/init.lua",
    "content": "local lib_panel = require('litee.lib.panel')\nlocal lib_state = require('litee.lib.state')\nlocal lib_util_buf = require('litee.lib.util.buffer')\nlocal config = require('litee.lib.config').config[\"term\"]\n\nlocal M = {}\n\nlocal opts = {noremap = true, silent=true}\nlocal function terminal_buf_setup(buf)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>v\", \"<cmd>lua require('configs.terminal').terminal_vsplit()<cr>\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>n\", \"<C-\\\\><C-n>\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>h\", \"<C-\\\\><C-n><C-w>h\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>j\", \"<C-\\\\><C-n><C-w>j\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>k\", \"<C-\\\\><C-n><C-w>k\", opts)\n    vim.api.nvim_buf_set_keymap(buf, 't', \"<C-w>l\", \"<C-\\\\><C-n><C-w>l\", opts)\n    vim.api.nvim_buf_set_option(buf, 'bufhidden', 'hide')\n\tif config.map_resize_keys then\n           lib_util_buf.map_resize_keys(config.position, buf, opts)\n    end\nend\nlocal function terminal_win_setup(win)\n    vim.api.nvim_win_set_option(win, 'winfixheight', true)\nend\n\n-- terminal opens a native Neovim terminal instance that\n-- is aware of the litee.panel layout.\n--\n-- the terminal will not truncate the panel if it is open\n-- on the left or right position.\n--\n-- the terminal can be opened at the top of bottom of the\n-- editor, but not left or right and this is configured\n-- via the 'litee.lib.config.term[\"position\"]' stanza.\n--\n-- the terminal has a fixed height so a call to <C-w>=\n-- does not effect the height and only evenly spaces\n-- any vsplit terminals in the pane.\n--\n-- the $SHELL environment variable must be set correctly\n-- to open the appropriate shell.\nfunction M.terminal()\n    local shell = vim.fn.getenv('SHELL')\n    if shell == nil or shell == \"\" then\n        return\n    end\n    local buf = vim.api.nvim_create_buf(false, false)\n    if buf == 0 then\n        vim.api.nvim_err_writeln(\"failed to create terminal buffer\")\n        return\n    end\n\n    terminal_buf_setup(buf)\n\n    if config.position == \"top\" then\n        vim.cmd('topleft split')\n    else\n        vim.cmd('botright split')\n    end\n    vim.cmd(\"resize \" .. config.term_size)\n    terminal_win_setup(vim.api.nvim_get_current_win())\n    local cur_win = vim.api.nvim_get_current_win()\n    local cur_tab = vim.api.nvim_get_current_tabpage()\n    local state = lib_state.get_state(cur_tab)\n    vim.api.nvim_win_set_buf(cur_win, buf)\n    vim.fn.termopen(shell)\n    if state ~= nil then\n        if lib_panel.is_panel_open(state) then\n            lib_panel.toggle_panel_ctx(true, true)\n        end\n    end\n    vim.api.nvim_set_current_win(cur_win)\nend\n\nfunction M.terminal_vsplit()\n    local shell = vim.fn.getenv('SHELL')\n    if shell == nil or shell == \"\" then\n        return\n    end\n    local buf = vim.api.nvim_create_buf(false, false)\n    if buf == 0 then\n        vim.api.nvim_err_writeln(\"failed to create terminal buffer\")\n        return\n    end\n    vim.cmd('vsplit')\n    local cur_win = vim.api.nvim_get_current_win()\n    terminal_win_setup(cur_win)\n    vim.api.nvim_win_set_buf(cur_win, buf)\n    vim.fn.termopen(shell)\n    terminal_buf_setup(buf)\nend\n\nfunction M.list_terminals()\n    local terms = {}\n    for _, b in ipairs(vim.api.nvim_list_bufs()) do\n        local buf_name = vim.api.nvim_buf_get_name(b)\n        if vim.fn.match(buf_name, \"term://\") == 0 then\n            table.insert(terms, {name = buf_name, buf = b})\n        end\n    end\n    if #terms == 0 then\n        return\n    end\n    vim.ui.select(\n        terms,\n        {\n            prompt = \"select a terminal to display\",\n            format_item = function(item)\n                return item[\"name\"] .. \" \" .. item[\"buf\"]\n            end\n        },\n        function (choice)\n            -- first see if there's a window that's opened with this term\n            for _, w in ipairs(vim.api.nvim_list_wins()) do\n                if vim.api.nvim_win_get_buf(w) == choice[\"buf\"] then\n                    vim.api.nvim_set_current_win(w)\n                    return\n                end\n            end\n\n            if config.position == \"top\" then\n                vim.cmd('topleft split')\n            else\n                vim.cmd('botright split')\n            end\n            vim.cmd(\"resize \" .. config.term_size)\n            local cur_win = vim.api.nvim_get_current_win()\n            local cur_tab = vim.api.nvim_get_current_tabpage()\n            local state = lib_state.get_state(cur_tab)\n            vim.api.nvim_win_set_buf(cur_win, choice[\"buf\"])\n            if state ~= nil then\n                if lib_panel.is_panel_open(state) then\n                    lib_panel.toggle_panel_ctx(true, true)\n                end\n            end\n            vim.api.nvim_set_current_win(cur_win)\n        end\n    )\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/tree/init.lua",
    "content": "local lib_marshal = require('litee.lib.tree.marshal')\n\nlocal M = {}\n\n-- registry keeps a mapping between tree handles\n-- and a tree table.\n--\n-- the registry and tree table stricture is defined\n-- below:\n-- {\n--   1: {root = {}, depth_table = {}, kind = \"\", source_line_map = nil, buf_line_map = nil}\n-- }\n-- 1 is the the associated handle returned by new_tree\n-- root is the root node of the tree\n--\n-- depth_table is the depth table associated with the tree\n--\n-- kind is the kind of tree and will typically be a component's\n-- name as defined in lib/state.lua\nlocal registry = {}\n\n-- new_tree registers an empty tree and returns\n-- the handle to the caller.\n--\n-- @param kind (string) A string representing, at\n-- a high level, the kind of tree being created.\n-- @returns tree_handle (int) A handle representing\n-- the created tree.\nfunction M.new_tree(kind)\n    local handle = #registry+1\n    registry[handle] = {root = {}, depth_table = {}, kind = kind}\n    return handle\nend\n\n-- get_tree takes a call handle and returns a table\n-- representing our tree components.\n--\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\n-- @returns tree (table) A tree table as defined\n-- in this module, see \"registry\" comments.\nfunction M.get_tree(handle)\n    local t = registry[handle]\n\n    -- attach marshaler info to tree if it exists.\n    if t ~= nil then\n        t.source_line_map = lib_marshal.source_line_map[handle]\n        t.buf_line_map = lib_marshal.buf_line_map[handle]\n    end\n\n    return registry[handle]\nend\n\n-- remove_tree takes a call handle and removes\n-- the associated tree from memory.\n--\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\nfunction M.remove_tree(handle)\n    if handle == nil then\n        return\n    end\n    if registry[handle] == nil then\n        return\n    end\n    registry[handle] = nil\nend\n\n-- search_dpt will search the dpt at the given\n-- depth for the given key.\n--\n-- @param dpt (table) A depth table retrieved\n-- from a previous call to get_tree.\n-- @param depth (int) The depth at which to search\n-- for the key\n-- @param key (string) The node's key to search\n-- for\n-- @returns node (table) If found, a node table\n-- as defined in lib/tree/node.lua. Nil if search\n-- fails.\nfunction M.search_dpt(dpt, depth, key)\n    local nodes = dpt[depth]\n    if nodes == nil then\n        return nil\n    end\n    for _, node in ipairs(nodes) do\n        if node.key == key then\n            return node\n        end\n    end\n    return nil\nend\n\n-- recursive_dpt_compute traverses the tree\n-- and flattens it into out depth_table\n--\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\nlocal function _recursive_dpt_compute(handle, node)\n    local depth = node.depth\n    if registry[handle].depth_table[depth] == nil then\n        registry[handle].depth_table[depth] = {}\n    end\n    table.insert(registry[handle].depth_table[depth], node)\n    -- recurse\n    for _, child in ipairs(node.children) do\n        _recursive_dpt_compute(handle, child)\n    end\nend\n\n-- _refresh_dpt dumps the current depth_table\n-- and writes a new one.\n--\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\nlocal function _refresh_dpt(handle)\n    registry[handle].depth_table = {}\n    _recursive_dpt_compute(handle, registry[handle].root)\nend\n\n-- add_node will add a node to the tree pointed to by the\n-- provided tree handle.\n--\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\n-- @param parent (table) The parent node table of the subtree being\n-- added. the parent's \"depth\" field is significant. setting it to\n-- 0 will throw away the current root and create a new tree.\n-- See usages of this function to understand how depth can be safely\n-- set.\n-- @param children (table) The children of the parent.\n-- the child's depth field has no significant and can be computed\n-- from the parents (unless external is used, see below).\n-- @param external (bool) If true an entire tree has been built externally\n-- and the root will be added to the tree without any modifications.\n-- the children param has no significance in this scenario.\n-- note: when using external the calling code must set the all parent\n-- and children depth fields correctly.\nfunction M.add_node(handle, parent, children, external)\n    if registry[handle] == nil then\n        return\n    end\n    -- external nodes are roots of trees built externally\n    -- if this is true set the tree's root to the incoming parent\n    -- and immediately return\n    if external then\n        registry[handle].root = parent\n        _refresh_dpt(handle)\n        return\n    end\n\n    -- if depth is 0 we are creating a new call tree.\n    if parent.depth == 0 then\n        registry[handle].root = parent\n        registry[handle].expanded = true\n        registry[handle].depth_table = {}\n        registry[handle].depth_table[0] = {}\n        table.insert(registry[handle].depth_table[0], registry[handle].root)\n    end\n\n    -- if parent's depth doesn't exist we can't\n    -- continue.\n    if registry[handle].depth_table[parent.depth] == nil then\n        -- this is an error\n        return\n    end\n\n    -- lookup parent node in depth tree (faster then tree diving.)\n    local pNode = nil\n    for _, node in pairs(registry[handle].depth_table[parent.depth]) do\n        if node.key == parent.key then\n            pNode = node\n            break\n        end\n    end\n    if pNode == nil then\n        return\n    end\n\n    -- ditch the old child array, we are refreshing the children\n    pNode.children = {}\n\n    local child_depth = parent.depth + 1\n    for _, child  in ipairs(children) do\n        child.depth = child_depth\n        table.insert(pNode.children, child)\n    end\n    _refresh_dpt(handle)\nend\n\n-- remove subtree will remove the subtree of the\n-- provided node, leaving the root node present.\n--\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua. This node must\n-- be the root of the subtree being removed.\n-- @param root (bool) Should be \"true\", indicator that\n-- recursion is at the root node.\nfunction M.remove_subtree(tree, node, root)\n    -- recurse to leafs\n    for _, child in ipairs(node.children) do\n        M.remove_subtree(tree, child, false)\n    end\n    if not root then\n        -- remove yourself from the depth table\n        local dt = registry[tree].depth_table[node.depth]\n        local nw_dt = {}\n        for _, dt_node in ipairs(dt) do\n            if dt_node.key ~= node.key then\n                table.insert(nw_dt, dt_node)\n            end\n        end\n        registry[tree].depth_table[node.depth] = nw_dt\n    end\n    if root then\n        -- remove your children\n        node.children = {}\n    end\nend\n\n-- collapse subtree will recursively collapse the\n-- subtree starting at root and inclusive to root.\n--\n-- this function does not modify the tree structure\n-- like \"remove_subtree\" but rather sets all nodes in the\n-- subtree to expanded = false. on next marshal of the\n-- tree the nodes will be collapsed.\n--\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua, this node must be\n-- the root of the subtree to be collapsed.\nfunction M.collapse_subtree(root)\n    root.expanded = false\n    for _, child in ipairs(root.children) do\n        M.collapse_subtree(child)\n    end\nend\n\n-- reparent_node will make the provided node\n-- the root of the provided tree, discarding\n-- any ancestors above it in the process.\n--\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\n--\n-- @param depth (int) The depth at which to search\n-- for the key\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua, this node must be\n-- the desired new root of the tree.\nfunction M.reparent_node(handle, depth, node)\n    -- we are the new root, dump the current root_node and\n    -- set yourself\n    if depth == 0 then\n        registry[handle].root = node\n        registry[handle].root.depth = 0\n    end\n    -- recurse to leafs\n    for _, child in ipairs(node.children) do\n        M.reparent_node(handle, depth+1, child)\n        -- recursion done, update your depth\n        child.depth = depth+1\n    end\n    if depth == 0 then\n        -- we are the root node, refresh depth_table with\n        -- new tree.\n        _refresh_dpt(handle)\n    end\nend\n\n-- dump_tree will dump the tree data structure to a\n-- buffer for debugging.\n--\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua, this node can be\n-- a root or a child depending on where in the tree\n-- you'd like to dump.\nfunction M.dump_tree(node)\n    local buf = vim.api.nvim_create_buf(true, false)\n    vim.api.nvim_buf_set_name(buf, \"calltree-dump\")\n    vim.cmd(\"botright split\")\n    local win = vim.api.nvim_get_current_win()\n    local lines = vim.fn.split(vim.inspect(node), \"\\n\")\n    vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)\n    vim.api.nvim_win_set_buf(win, buf)\n    vim.api.nvim_set_current_win(win)\nend\n\n-- write_tree recursively marshals all nodes from the provided root\n-- down, into UI lines and writes those lines to the provided buffer.\n--\n-- @param buf  (int) The buffer handle to write the marshalled tree to\n-- @param tree (int) The tree handle to marshal into the provided buffer\n-- @param marshal_func (function(node)) A function\n-- when given a node returns the following strings\n    -- name: the display name for the node\n    -- detail: details to display about the node\n    -- icon: any icon associated with the node\nfunction M.write_tree(buf, tree, marshal_func, no_guide_leaf)\n    local root = registry[tree].root\n    if root == nil then\n        return\n    end\n    lib_marshal._marshal_tree(buf, {}, root, tree, {}, marshal_func, no_guide_leaf)\n    return buf\nend\n\n-- same as `write_tree` but forces `no_guide_leaf` to be true\n-- on each call.\n--\n-- useful for clients of the lib which always choose this option.\nfunction M.write_tree_no_guide_leaf(buf, tree, marshal_func)\n    M.write_tree(buf, tree, marshal_func, true)\nend\n\n-- marshal_line takes a UI buffer line and\n-- marshals it into a tree.Node.\n--\n-- @param linenr (table) A buffer line as returned by\n-- vim.api.nvim_win_get_cursor()\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\n--\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua, nil if\n-- marshal failed.\nfunction M.marshal_line(linenr, handle)\n    return lib_marshal.marshal_line(linenr, handle)\nend\n\nfunction M.flatten_depth_table(dtp)\n    local nodes = {}\n    for _, depth in pairs(dtp) do\n        for _, node in ipairs(depth) do\n            table.insert(nodes, node)\n        end\n    end\n    return nodes\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/tree/marshal/init.lua",
    "content": "local lib_util = require('litee.lib.util')\nlocal lib_hi    = require('litee.lib.highlights')\nlocal lib_tree_config = require('litee.lib.config').config[\"tree\"]\nlocal icon_set = require('litee.lib').icon_set\n\nlocal M = {}\n\n-- buf_line_map keeps a mapping between marshaled\n-- buffer lines and the node objects for a given tree.\n--\n-- the structure of this table is as follows:\n-- {\n--   tree_handle = {\n--      line_number = node,\n--      ...\n--   },\n--   ...\n-- }\nM.buf_line_map = {}\n\n-- maps source code lines to buffer lines\n-- for a given tree.\n--\n-- currently only useful for symboltree.\n--\n-- the struture of this table is as follows:\n-- {\n--   tree_handle = {\n--      source_file_line_number = {\n--          uri = relative_path_to_file,\n--          line = calltree_buffer_line_number\n--      }\n--      ...\n--   }\n--   ...\n-- }\nM.source_line_map = {}\n\n-- marshal_node takes a node and a marshal_func and\n-- produces a buffer line.\n--\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua, this node must\n-- be the node being marshalled into a line.\n-- @param marshal_func (function(node)) A function\n-- when given a node returns the following strings\n-- name: the display name for the node\n-- detail: details to display about the node\n-- icon: any icon associated with the node\n-- expand_guide: optional override when the marshal\n-- func want to specify a specific expand guide.\n-- @param no_guide_leaf (bool) If node is a leaf\n-- node and this bool is true an expansion guide\n-- will be ommited from the rendered line.\n-- @return buffer_line (string) a string with\n-- the preamble of the buffer line.\n-- @return virt_text (table) A table suitable for\n-- configuring virtual text containing the details\n-- of the node. This virtual text will be placed EOL\n-- in the buffer line.\nfunction M.marshal_node(node, marshal_func, no_guide_leaf)\n    local expand_guide = \"\"\n    if node.expanded then\n        expand_guide = icon_set[\"Expanded\"]\n    else\n        expand_guide = icon_set[\"Collapsed\"]\n    end\n    if no_guide_leaf\n        and #node.children == 0\n        and node.expanded == true\n    then\n        expand_guide = icon_set[\"Space\"]\n    end\n\n    local str = \"\"\n\n    local name, detail, icon, expand_guide_override = marshal_func(node)\n\n    if expand_guide_override ~= nil then\n        expand_guide = expand_guide_override\n    end\n\n    if lib_tree_config.indent_guides then\n        for i=1, node.depth do\n            if i == 1 then\n                str = str .. icon_set[\"Space\"]\n            else\n                str = str .. icon_set[\"IndentGuide\"] .. icon_set[\"Space\"]\n            end\n        end\n    else\n        for _=1, node.depth do\n            str = str .. icon_set[\"Space\"]\n        end\n    end\n\n    if icon == nil then\n        icon = \" \"\n    end\n\n    -- ▶ Func1\n    str = str .. expand_guide .. icon_set[\"Space\"]\n    str = str .. icon .. icon_set[\"Space\"]  .. icon_set[\"Space\"] .. name\n    -- return detail as virtual text chunk.\n    return str, {{detail, lib_hi.hls.SymbolDetailHL}}\nend\n\n-- marshal_line takes a UI buffer line and\n-- marshals it into a tree.Node.\n--\n-- @param linenr (table) A buffer line as returned by\n-- vim.api.nvim_win_get_cursor()\n-- @param handle (int) A tree handle ID previously\n-- returned from a call to new_tree\n--\n-- @param node (table) A node table\n-- as defined in lib/tree/node.lua, nil if\n-- marshal failed.\nfunction M.marshal_line(linenr, handle)\n    if M.buf_line_map == nil then\n        return nil\n    end\n    if M.buf_line_map[handle] == nil then\n        return nil\n    end\n    local node = M.buf_line_map[handle][linenr[1]]\n    return node\nend\n\n-- marshal_tree recursively marshals all nodes from the provided root\n-- down, into UI lines.\n--\n-- @param buf (int) The buffer handle to write the marshalled tree to\n-- @param lines (list of string) Recursive accumlator of marshaled\n-- lines. Start this function with an empty table.\n-- @param node (table) A node table as defined in lib/tree/node.lua,\n-- this node must be the root  of the tree being marshalled into buffer lines.\n-- @param virtual_text_lines (list of string) Recursive accumlator of marshaled\n-- virtual text lines. Start this function with an empty table.\n-- @param marshal_func (function(node)) A function\n-- when given a node returns the following strings\n    -- name: the display name for the node\n    -- detail: details to display about the node\n    -- icon: any icon associated with the node\nfunction M._marshal_tree(buf, lines, node, tree, virtual_text_lines, marshal_func, no_guide_leaf)\n    if node.depth == 0 then\n        virtual_text_lines = {}\n        -- create a new line mapping\n        M.buf_line_map[tree] = {}\n        M.source_line_map[tree] = {}\n    end\n\n    local line, virtual_text = M.marshal_node(node, marshal_func, no_guide_leaf)\n    table.insert(lines, line)\n    table.insert(virtual_text_lines, virtual_text)\n    M.buf_line_map[tree][#lines] = node\n\n    -- if the node has a location we can track where it\n    -- exists in the source code file.\n    if node.location ~= nil and not vim.tbl_isempty(node.location) then\n        local start_line = node.location[\"range\"][\"start\"].line\n        M.source_line_map[tree][start_line+1] = {\n            uri = lib_util.absolute_path_from_uri(node.location.uri),\n            line = #lines\n        }\n    end\n\n    -- if we are an expanded node or we are the root (always expand)\n    -- recurse\n    if node.expanded  or node.depth == 0 then\n        for _, child in ipairs(node.children) do\n            M._marshal_tree(buf, lines, child, tree, virtual_text_lines, marshal_func, no_guide_leaf)\n        end\n    end\n\n    -- we are back at the root, all lines are inserted, lets write it out\n    -- to the buffer\n    if node.depth == 0 then\n        vim.api.nvim_buf_set_option(buf, 'modifiable', true)\n        vim.api.nvim_buf_set_lines(buf, 0, -1, true, {})\n        vim.api.nvim_buf_set_lines(buf, 0, #lines, false, lines)\n        vim.api.nvim_buf_set_option(buf, 'modifiable', false)\n        for i, vt in ipairs(virtual_text_lines) do\n            if vt[1][1] == \"\" then\n                goto continue\n            end\n            local opts = {\n                virt_text = vt,\n                virt_text_pos = 'eol',\n                hl_mode = 'combine'\n            }\n            vim.api.nvim_buf_set_extmark(buf, 1, i-1, 0, opts)\n            ::continue::\n        end\n    end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/tree/node.lua",
    "content": "local M = {}\n\n-- new_node creates a polymorphic node\n-- which the caller can attach their own\n-- node specific fields to.\n--\n-- a unique key must be generated and provided\n-- along with the desired depth of the node with\n-- the tree it will belong in.\n--\n-- see function definition for node field documentation.\n-- only the requird fields are present in the constructor\n-- optional fields can be added on to the node by the caller.\n--\n-- @param name (string) a non-unique display name\n-- for the node.\n-- @param key (string) a unique key used to identify\n-- the node when placed into a tree.\n-- @param depth (int) the node's depth in the tree, zero\n-- indexed. depth 0 indicates this node is the root of\n-- the tree.\n-- @returns (table) A table representing a node object.\n-- the caller is free to attach domain specific fields\n-- that convey the node's purpose othorgonal to the usage\n-- in the tree.\nfunction M.new_node(name, key, depth)\n    return {\n        -- a non-unique display name for the node\n        name = name,\n        -- the depth of the node in the target tree\n        depth = depth,\n        -- a unique key used to identify the node when\n        -- placed into a tree\n        key = key,\n        -- a list of children nodes with recursive definitions.\n        children = {},\n        -- a \"Location\" object as defined by the LSP which\n        -- associates this node with a source code file and line range.\n        -- see:\n        -- https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#location\n        location = {},\n        -- a list of \"Range\" objects, relative to the above location object,\n        -- which relate in a domain specific way to this node.\n        -- see:\n        -- https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#range\n        references = {},\n        -- whether this node is expanded in its containing\n        -- tree.\n        expanded = false,\n        offset_encoding = \"utf-8\"\n    }\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/util/buffer.lua",
    "content": "local M = {}\n\n\nlocal original_guicursor = \"\"\n-- hide_cursor will dynamically create the LTCursorHide hi and\n-- set the guicursor option to this hi group.\n--\n-- the LTCursorHide hi has the same bg/fg as the CursorLine hi which\n-- is used inside the LITEE.nvim windows.\n--\n-- this effectively hides the cursor by making it blend into the cursor\n-- line.\n--\n-- hide : bool - if true hides the cursor if false sets the guicursor\n-- option back to the value when Neovim started.\nfunction M.hide_cursor(hide)\n    if original_guicursor == \"\" then\n        for _, section in ipairs(vim.opt.guicursor:get()) do\n            original_guicursor = original_guicursor .. section .. ','\n        end\n    end\n    if not hide then\n        vim.cmd('set guicursor=' .. original_guicursor)\n        return\n    end\n    local colors_rgb = vim.api.nvim_get_hl_by_name(\"CursorLine\", true)\n    local colors_256 = vim.api.nvim_get_hl_by_name(\"CursorLine\", false)\n    local hi = string.format(\"hi LTCursorHide cterm=None ctermbg=%s ctermfg=%s gui=None guibg=%s guifg=%s\",\n        (function() if colors_256.background ~= nil then return colors_256.background else return \"None\" end end)(),\n        (function() if colors_256.foreground ~= nil then return colors_256.foreground else return \"None\" end end)(),\n        (function() if colors_rgb.background ~= nil then return string.format(\"#%x\", colors_rgb.background) else return \"None\" end end)(),\n        (function() if colors_rgb.foreground ~= nil then return string.format(\"#%x\", colors_rgb.foreground) else return \"None\" end end)()\n    )\n    vim.cmd(hi)\n    local cursorgui = \"set guicursor=n:LTCursorHide\"\n    vim.cmd(cursorgui)\nend\n\n-- set_scrolloff will enable a global scrolloff\n-- of 999 when set is true.\n--\n-- when set is false the scrolloff will be set back to 0.\n-- useful for keeping the contents of a litee panel centered.\nfunction M.set_scrolloff(set)\n    if set then\n        vim.cmd(\"set scrolloff=999\")\n    else\n        vim.cmd(\"set scrolloff=0\")\n    end\nend\n\nfunction M.map_resize_keys(orientation, buffer_handle, opts)\n    if orientation == \"top\" then\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Right>\", \":vert resize +5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Left>\", \":vert resize -5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Up>\", \":resize +5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Down>\", \":resize -5<cr>\", opts)\n    elseif orientation == \"bottom\" then\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Right>\", \":vert resize +5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Left>\", \":vert resize -5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Down>\", \":resize +5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Up>\", \":resize -5<cr>\", opts)\n    elseif orientation == \"left\" then\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Up>\", \":resize +5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Down>\", \":resize -5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Left>\", \":vert resize -5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Right>\", \":vert resize +5<cr>\", opts)\n    elseif orientation == \"right\" then\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Up>\", \":resize +5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Down>\", \":resize -5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Left>\", \":vert resize +5<cr>\", opts)\n        vim.api.nvim_buf_set_keymap(buffer_handle, \"n\", \"<Right>\", \":vert resize -5<cr>\", opts)\n    end\nend\n\n-- a convenience method which will close any popups\n-- generated by the litee library (not notifications).\nfunction M.close_all_popups()\n    require('litee.lib.lsp.hover').close_hover_popup()\n    require('litee.lib.details').close_details_popup()\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/util/init.lua",
    "content": "local M = {}\n\nfunction M.absolute_path_from_uri(uri)\n    local uri_path = vim.fn.substitute(uri, \"file://\", \"\", \"\")\n    return uri_path\nend\n\n-- safe_cursor_reset will attempt to move the\n-- cursor to `linenr`, if the provided `linenr`\n-- would overflow the buffer the cursor will\n-- safely be placed at the lowest available\n-- buffer line.\nfunction M.safe_cursor_reset(win, linenr)\n    if\n        win == nil\n        or not vim.api.nvim_win_is_valid(win)\n        or linenr == nil\n    then\n        return\n    end\n    local lc = vim.api.nvim_buf_line_count(vim.api.nvim_win_get_buf(win))\n    if lc < linenr[1] then\n        linenr[1] = lc\n    end\n    vim.api.nvim_win_set_cursor(win, linenr)\nend\n\nfunction M.relative_path_from_uri(uri)\n    local cwd = vim.fn.getcwd()\n    local uri_path = vim.fn.substitute(uri, \"file://\", \"\", \"\")\n    local idx = vim.fn.stridx(uri_path, cwd)\n    if idx == -1 then\n        -- we can't resolve a relative path, just give the\n        -- full path to the file.\n        return uri_path, false\n    end\n    return vim.fn.substitute(uri_path, cwd .. \"/\", \"\", \"\"), true\nend\n\nfunction M.resolve_location(node)\n    local location = nil\n    if node.symbol ~= nil then\n        location = node.symbol.location\n    elseif node.call_hierarchy_item ~= nil then\n        location = {\n            uri = node.call_hierarchy_item.uri,\n            range = node.call_hierarchy_item.range\n        }\n    elseif node.document_symbol ~= nil then\n        location = {\n            uri = node.uri,\n            range = node.document_symbol.selectionRange\n        }\n    elseif node.filetree_item ~= nil then\n        local range = {}\n        range[\"start\"] = { line = 0, character = 0}\n        range[\"end\"] = { line = 0, character = 0}\n        location = {\n            uri = \"file://\" .. node.filetree_item.uri,\n            range = range\n        }\n    end\n    return location\nend\n\nfunction M.resolve_absolute_file_path(node)\n    if node.symbol ~= nil then\n        local uri = node.symbol.location.uri\n        return M.absolute_path_from_uri(uri)\n    elseif node.call_hierarchy_item ~= nil then\n        local uri = node.call_hierarchy_item.uri\n        return M.absolute_path_from_uri(uri)\n    elseif node.document_symbol ~= nil then\n        local uri = node.uri\n        return M.absolute_path_from_uri(uri)\n    else\n        return nil\n    end\nend\n\nfunction M.resolve_hover_params(node)\n    local params = {}\n    if node.symbol ~= nil then\n        params.textDocument = {\n            uri = node.symbol.location.uri\n        }\n        params.position = {\n            line = node.symbol.location.range.start.line,\n            character = node.symbol.location.range.start.character\n        }\n    elseif node.call_hierarchy_item ~= nil then\n        params.textDocument = {\n            uri = node.call_hierarchy_item.uri\n        }\n        params.position = {\n            line = node.call_hierarchy_item.range.start.line,\n            character = node.call_hierarchy_item.range.start.character\n        }\n    elseif node.document_symbol ~= nil then\n        params.textDocument = {\n            uri = node.uri\n        }\n        params.position = {\n            line = node.document_symbol.selectionRange.start.line,\n            character = node.document_symbol.selectionRange.start.character\n        }\n    else\n        return nil\n    end\n    return params\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/util/path.lua",
    "content": "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 encoding filesystem paths\n-- to a string that can be used as a filename.\n--\n-- the encoding is just a sub-set of URL encoding.\n--\n-- @param str (string) The string to encode.\nfunction M.safe_encode(str)\n    str, _ = string.gsub(str, '/', '%%2F')\n    str, _ = string.gsub(str, ' ', '%%20')\n    str, _ = string.gsub(str, ':', '%%3A')\n    return str\nend\n\n-- decodes a string encoded by safe_encode.\n-- see safe_encode for details.\nfunction M.safe_decode(str)\n    str, _ = string.gsub(str, '%%2F', '/')\n    str, _ = string.gsub(str, '%%20', ' ')\n    str, _ = string.gsub(str, '%%3A', ':')\n    return str\nend\n\nfunction M.is_dir(path)\n    if vim.fn.isdirectory(path) == 0 then\n        return false\n    end\n    return true\nend\n\nfunction M.file_exists(path)\n    if vim.fn.filereadable(path) == 0 then\n        return false\n    end\n    return true\nend\n\nfunction M.relative_path_from_uri(uri)\n    local cwd = vim.fn.getcwd()\n    local uri_path = vim.fn.substitute(uri, \"file://\", \"\", \"\")\n    local idx = vim.fn.stridx(uri_path, cwd)\n    if idx == -1 then\n        -- we can't resolve a relative path, just give the\n        -- full path to the file.\n        return uri_path, false\n    end\n    return vim.fn.substitute(uri_path, cwd .. \"/\", \"\", \"\"), true\nend\n\n-- provides the filename with no path details for\n-- the provided uri.\nfunction M.basename(uri)\n    local final_sep = vim.fn.strridx(uri, \"/\")\n    local uri_len   = vim.fn.strlen(uri)\n\n    -- if its a dir, remove final \"/\"\n    if final_sep+1 == uri_len then\n        uri = vim.fn.strpart(uri, 0, uri_len-1)\n        final_sep = vim.fn.strridx(uri, \"/\")\n    end\n\n    local dir = vim.fn.strpart(uri, final_sep+1, vim.fn.strlen(uri))\n    return dir\nend\n\nfunction M.parent_dir(path)\n        local base = M.basename(path)\n        local diff = vim.fn.strlen(path) - (vim.fn.strlen(base)+1)\n        local res = vim.fn.strpart(path, 0, diff)\n        if vim.fn.strridx(path, \"/\") == #path-1 then\n            return res\n        else\n            return res .. \"/\"\n        end\nend\n\nfunction M.path_prefix_match(prefix, path)\n    local idx = vim.fn.stridx(path, prefix)\n    if idx == -1 then\n        return false\n    end\n    return true\nend\n\nfunction M.swap_path_prefix(path, old_prefix, new_prefix)\n    local new_path = vim.fn.substitute(path, old_prefix, new_prefix, \"\")\n    return new_path\nend\n\nfunction M.strip_file_prefix(path)\n    return vim.fn.substitute(path, \"file://\", \"\", \"\")\nend\n\nfunction M.add_file_prefix(path)\n    vim.fn.substitute(path, \"file://\", \"\", \"\")\n    return string.format(\"%s%s\", \"file://\", path)\nend\n\nfunction M.strip_trailing_slash(path)\n    if vim.fn.strridx(path, \"/\") == (vim.fn.strlen(path)-1) then\n        return vim.fn.strpart(path, 0, vim.fn.strlen(path)-1)\n    end\n    return path\nend\n\n-- strip the prefix from the path, usually to make a\n-- relative path, and ensure leading '/'\nfunction M.strip_path_prefix(prefix, path)\n    local new = vim.fn.substitute(path, prefix, \"\", \"\")\n    if vim.fn.strridx(new, '/') == -1 then\n        new = '/' .. new\n    end\n    return new\nend\n\nreturn M\n"
  },
  {
    "path": "lua/litee/lib/util/window.lua",
    "content": "local lib_state         = require('litee.lib.state')\nlocal lib_tree_config   = require('litee.lib.config').config[\"tree\"]\nlocal lib_icons         = require('litee.lib.icons')\nlocal lib_hi            = require('litee.lib.highlights')\n\nlocal M = {}\n\n-- a convenience function for setting up tree window highlights\n-- suitable for being ran inside a \"post_window_create\"\n-- function.\n--\n-- see lib.tree.register_component for more details.\nfunction M.set_tree_highlights()\n    local icon_set = nil\n    if lib_tree_config.icon_set == nil then\n        icon_set = lib_icons[\"default\"]\n    else\n        icon_set = lib_icons[lib_tree_config.icon_set]\n    end\n    -- set configured icon highlights\n    for icon, hl in pairs(lib_icons.icon_hls) do\n        vim.cmd(string.format(\"syn match %s /\\\\<%s\\\\>/\", hl, icon_set[icon]))\n    end\n    -- set configured symbol highlight\n    vim.cmd(string.format(\"syn match %s /%s/\", lib_hi.hls.SymbolHL, [[\\w]]))\n    vim.cmd(string.format(\"syn match %s /%s/\", lib_hi.hls.SymbolHL, [[\\.]]))\n    vim.cmd(string.format(\"syn match %s /%s/\", lib_hi.hls.SymbolHL, [[\\-]]))\n    vim.cmd(string.format(\"syn match %s /%s/\", lib_hi.hls.SymbolHL, [[\\\\_]]))\n    -- set configured expanded indicator highlights\n    vim.cmd(string.format(\"syn match %s /\\\\<%s\\\\>/\", lib_hi.hls.ExpandedGuideHL, icon_set[\"Expanded\"]))\n    vim.cmd(string.format(\"syn match %s /\\\\<%s\\\\>/\", lib_hi.hls.CollapsedGuideHL, icon_set[\"Collapsed\"]))\n    -- set configured indent guide highlight\n    vim.cmd(string.format(\"syn match %s /\\\\<%s\\\\>/\", lib_hi.hls.IndentGuideHL, icon_set[\"Guide\"]))\nend\n\n-- inside_component_win is a helper functions which\n-- tells the caller if the currently focused window\n-- is a litee.nvim registered component window.\nfunction M.inside_component_win()\n    local tab = vim.api.nvim_get_current_tabpage()\n    local win = vim.api.nvim_get_current_win()\n    local state = lib_state.get_state(tab)\n    if state == nil then\n        return false\n    end\n    local active_components = lib_state.get_active_components(tab)\n\n    local in_litee_panel = false\n    for _, active_component in ipairs(active_components) do\n        if win == state[active_component].win then\n            in_litee_panel = true\n        end\n    end\n\n    return in_litee_panel\nend\n\n-- is_component_win takes a tab and a window and returns\n-- true if the provided window is a registered litee panel\n-- window and false if not.\n--\n-- @param tab (int) A tab ID.\n-- @param win (int) A window which resides in tab that\n-- will be evaluated.\nfunction M.is_component_win(tab, win)\n    local active_components = lib_state.get_active_components(tab)\n    local state = lib_state.get_state(tab)\n    local is_litee_panel = false\n    for _, active_component in ipairs(active_components) do\n        if win == state[active_component].win then\n            is_litee_panel = true\n        end\n    end\n    return is_litee_panel\nend\n\nreturn M\n"
  }
]