From db24f06633834db06e90fa8766e86a3c8c9bca7d Mon Sep 17 00:00:00 2001 From: alemi Date: Sat, 24 Aug 2024 01:58:03 +0200 Subject: [PATCH] feat: use neo-tree if available for tree view must also add it to registered sources: add `codemp.neo-tree` and done --- src/neo-tree/bridge.lua | 132 ++++++++++++++++++++++++++++++++++++ src/neo-tree/commands.lua | 69 +++++++++++++++++++ src/neo-tree/components.lua | 84 +++++++++++++++++++++++ src/neo-tree/init.lua | 45 ++++++++++++ src/window.lua | 16 ++++- src/workspace.lua | 20 ++++++ 6 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 src/neo-tree/bridge.lua create mode 100644 src/neo-tree/commands.lua create mode 100644 src/neo-tree/components.lua create mode 100644 src/neo-tree/init.lua diff --git a/src/neo-tree/bridge.lua b/src/neo-tree/bridge.lua new file mode 100644 index 0000000..26411ac --- /dev/null +++ b/src/neo-tree/bridge.lua @@ -0,0 +1,132 @@ +local renderer = require("neo-tree.ui.renderer") +local codemp = require("codemp.session") +local cc = require("neo-tree.sources.common.commands") +local buf_manager = require("codemp.buffers") + +local M = {} + +---@class Item +---@field id string +---@field name string +---@field type string +---@field loaded any +---@field filtered_by any +---@field extra table +---@field is_nested any +---@field skip_node any +---@field is_empty_with_hidden_root any +---@field stat any +---@field stat_provider any +---@field is_link any +---@field link_to any +---@field path any +---@field ext any +---@field search_pattern any + +---@param workspace string workspace name +---@param path string buffer relative path +---@return Item +local function new_item(workspace, path) + return { + id = string.format("codemp://%s/%s", workspace, path), + name = path, + type = "buffer", + extra = {}, + children = {}, + } +end + +---@param workspace string workspace name +---@param username string user display name +---@return Item +local function new_user(workspace, username) + return { + id = string.format("codemp://%s@%s", username, workspace), + name = username, + type = "user", + extra = {}, + children = {}, + } +end + +---@param name string workspace name +---@param owned boolean true if this workspace is owned by us +---@param expanded? boolean if node should be pre-expanded +---@return Item +local function new_workspace(name, owned, expanded) + return { + id = "codemp://" .. name, + name = name, + type = "workspace", + ['_is_expanded'] = expanded, -- TODO this is nasty can we do better? + extra = { + owned = owned, + }, + children = {}, + } +end + +local function spacer() + return { + id = "codemp-ws-spacer-" .. vim.fn.rand() % 1024, + name = "", + type = "spacer", + } +end + +M.update_state = function(state) + ---@type Item + local root + + if codemp.workspace ~= nil then + root = { + id = "codemp", + name = codemp.client.username .. "@" .. codemp.workspace.name, + type = "root", + extra = {}, + children = {} + } + table.insert(root.children, spacer()) + for i, path in ipairs(codemp.workspace:filetree()) do + table.insert(root.children, new_item(codemp.workspace.name, path)) + end + table.insert(root.children, spacer()) + for user, buffer in pairs(buf_manager.users) do + table.insert(root.children, new_user(codemp.workspace.name, user)) + end + elseif codemp.client ~= nil then + root = { + id = "codemp", + name = codemp.client.username .. "@codemp", + type = "root", + extra = {}, + children = {} + } + for _, ws in ipairs(codemp.available) do + local workspace = new_workspace(ws.name, ws.owned) + + if codemp.workspace ~= nil and codemp.workspace.name == ws.name then + end + + table.insert(root.children, workspace) + end + else + root = { + id = "codemp", + name = "codemp", + type = "root", + extra = {}, + children = {} + } + end + + renderer.show_nodes({ root }, state) + + if codemp.workspace ~= nil then + for _, node in ipairs(state.tree:get_nodes()) do + node:expand() + end + end +end + +return M diff --git a/src/neo-tree/commands.lua b/src/neo-tree/commands.lua new file mode 100644 index 0000000..47f0116 --- /dev/null +++ b/src/neo-tree/commands.lua @@ -0,0 +1,69 @@ +local cc = require("neo-tree.sources.common.commands") +local utils = require("neo-tree.utils") +local manager = require("neo-tree.sources.manager") +local session = require("codemp.session") +local renderer = require("neo-tree.ui.renderer") +local ws_manager = require("codemp.workspace") +local buf_manager = require("codemp.buffers") +local client_manager = require("codemp.client") + +local M = {} + +M.refresh = require("neo-tree.utils").wrap(manager.refresh, "codemp") + +M.open = function(state, path, extra) + local selected = state.tree:get_node() + if selected.type == "spacer" then return end + if selected.type == "root" then + if session.client ~= nil then + print(" +-+ connected to codemp as " .. session.client.username) + else + client_manager.connect() + end + return + end + if selected.type == "workspace" then + if selected:is_expanded() then + vim.ui.input({ prompt = "disconnect from workspace?" }, function (input) + if input == nil then return end + if input ~= "y" then return end + ws_manager.leave() + selected:collapse() + manager.refresh("codemp") + end) + else + if session.workspace ~= nil and session.workspace.name ~= selected.name then + error("must leave current workspace first") + end + if session.workspace == nil then + ws_manager.join(selected.name) + end + selected:expand() + manager.refresh("codemp") + end + return + end + if selected.type == "buffer" then + local window = utils.get_appropriate_window(state) + vim.api.nvim_set_current_win(window) + buf_manager.attach(selected.name) + return + end + if selected.type == "user" then + print("another remote user") + return + end + error("unrecognized node type") +end + +M.add = function(_state) + if session.workspace == nil then error("not in a workspace") end + vim.ui.input({ prompt = "name" }, function(input) + if input == nil or input == "" then return end + session.workspace:create_buffer(input):await() + manager.refresh("codemp") + end) +end + +cc._add_common_commands(M) +return M diff --git a/src/neo-tree/components.lua b/src/neo-tree/components.lua new file mode 100644 index 0000000..ebad9c0 --- /dev/null +++ b/src/neo-tree/components.lua @@ -0,0 +1,84 @@ +-- This file contains the built-in components. Each componment is a function +-- that takes the following arguments: +-- config: A table containing the configuration provided by the user +-- when declaring this component in their renderer config. +-- node: A NuiNode object for the currently focused node. +-- state: The current state of the source providing the items. +-- +-- The function should return either a table, or a list of tables, each of which +-- contains the following keys: +-- text: The text to display for this item. +-- highlight: The highlight group to apply to this text. + +local highlights = require("neo-tree.ui.highlights") +local common = require("neo-tree.sources.common.components") +local codemp_utils = require("codemp.utils") +local codemp_buffers = require("codemp.buffers") + +local M = {} + +M.icon = function(config, node, state) + local icon, highlight + if node.type == "buffer" then + icon = "- " + highlight = highlights.FILE_ICON + elseif node.type == "directory" then + icon = "= " + highlight = highlights.DIRECTORY_ICON + elseif node.type == "root" then + icon = "> " + highlight = highlights.FILE_STATS_HEADER + elseif node.type == "workspace" then + if node:is_expanded() then + icon = "| " + else + icon = "+ " + end + highlight = highlights.SYMBOLIC_LINK_TARGET + elseif node.type == "user" then + icon = ":" + highlight = codemp_utils.color(node.name) + end + + return { + text = icon, + highlight = highlight, + } +end + +M.name = function(config, node, state) + local highlight = config.highlight or highlights.FILE_NAME + if node.type == "root" then + highlight = highlights.ROOT_NAME + elseif node.type == "workspace" then + highlight = highlights.SYMBOLIC_LINK_TARGET + end + return { + text = node.name, + highlight = highlight, + } +end + +M.spacer = function(config, node, state) + return { + text = " ", + highlight = highlights.NORMAL, + } +end + +M.users = function(config, node, state) + local out = {} + -- TODO this is rather inefficient, maybe store reverse map precalculated? + for user, buf in pairs(codemp_buffers.users) do + if buf == node.name then + table.insert(out, { + text = " ", + highlight = codemp_utils.color(user), + align = "right", + }) + end + end + return out +end + +return vim.tbl_deep_extend("force", common, M) diff --git a/src/neo-tree/init.lua b/src/neo-tree/init.lua new file mode 100644 index 0000000..68b67ff --- /dev/null +++ b/src/neo-tree/init.lua @@ -0,0 +1,45 @@ +local bridge = require("codemp.neo-tree.bridge") + +local M = { name = "codemp" } + +M.navigate = function(state, path) + if path == nil then + path = vim.fn.getcwd() + end + state.path = path + bridge.update_state(state) +end + +M.setup = function(config, global_config) +end + +M.default_config = { + renderers = { + spacer = { + { "indent" }, + }, + root = { + { "icon" }, + { "name" }, + }, + workspace = { + { "indent" }, + { "icon" }, + { "name" }, + }, + user = { + { "indent" }, + { "icon" }, + { "name" }, + }, + buffer = { + { "indent" }, + { "icon" }, + { "name" }, + { "spacer" }, + { "users" }, + }, + }, +} + +return M diff --git a/src/window.lua b/src/window.lua index f305574..25ea5cc 100644 --- a/src/window.lua +++ b/src/window.lua @@ -1,3 +1,17 @@ +local success, manager = pcall(require, "neo-tree.sources.manager") +if success then + -- we have Neotree installed! use it for cool tree view + return { + update = function () manager.refresh("codemp") end, + init = function () end, + open = function () vim.cmd(":Neotree open source=codemp") end, + toggle = function () vim.cmd(":Neotree toggle source=codemp") end, + } +end + +-- we don't have Neotree installed, cook a rough window + + local session = require('codemp.session') local utils = require('codemp.utils') local buffers = require('codemp.buffers') @@ -144,6 +158,4 @@ return { open = open_window, update = update_window, toggle = toggle_window, - buffer = buffer_id, - id = window_id, } diff --git a/src/workspace.lua b/src/workspace.lua index 9f79479..f5cb20b 100644 --- a/src/workspace.lua +++ b/src/workspace.lua @@ -5,6 +5,25 @@ local window = require('codemp.window') local user_hl = {} +local function fetch_workspaces_list(client) + local new_list = {} + local owned = client:list_workspaces(true, false):await() + for _, ws in pairs(owned) do + table.insert(new_list, { + name = ws, + owned = true, + }) + end + local invited = client:list_workspaces(false, true):await() + for _, ws in pairs(invited) do + table.insert(new_list, { + name = ws, + owned = false, + }) + end + return new_list +end + ---@param ws Workspace local function register_cursor_callback(ws) local controller = ws.cursor @@ -97,4 +116,5 @@ return { join = join, leave = leave, map = user_hl, + list = fetch_workspaces_list, }