Compare commits
24 Commits
4deec5b313
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5dab9b2499 | |||
| 0f73cbcb92 | |||
| fc930deb4b | |||
| 459fa712d9 | |||
| 6f1adc9381 | |||
| 1af2b4cc7d | |||
| 018b471b72 | |||
| 7f725c6530 | |||
| 508ebdb0c0 | |||
| 4d56666323 | |||
| 306fa774af | |||
| 9a2b77fe5f | |||
| c0ae23a60d | |||
| d73bcbaa9b | |||
| c6c794ff7d | |||
| a42316e692 | |||
| 4010131ed0 | |||
| b465245c46 | |||
| b05ed0b5aa | |||
| 8a6bb48755 | |||
| 9358f55818 | |||
| 80b70edcaa | |||
| 049160ceac | |||
| 79a2f35cec |
@@ -0,0 +1 @@
|
||||
lazy-lock.json
|
||||
@@ -24,4 +24,4 @@ if not pcall(require, "lazy") then
|
||||
end
|
||||
|
||||
require "lazy_setup"
|
||||
require "polish"
|
||||
require "polish.init"
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"AstroNvim": { "branch": "main", "commit": "9417da143b971e65b159089c3de5a0ee37edb1fd" },
|
||||
"Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" },
|
||||
"LuaSnip": { "branch": "master", "commit": "458560534a73f7f8d7a11a146c801db00b081df0" },
|
||||
"aerial.nvim": { "branch": "master", "commit": "3284a2cb858ba009c79da87d5e010ccee3c99c4d" },
|
||||
"astrocore": { "branch": "main", "commit": "c797dd5a592e2bd154f2503e231b8a4083659534" },
|
||||
"astrolsp": { "branch": "main", "commit": "414775e4b49a46bd7105cc5498ea7bb312359bf2" },
|
||||
"astrotheme": { "branch": "main", "commit": "f12dcf64b1f9a05839c3ac2146f550f43bae9dab" },
|
||||
"astroui": { "branch": "main", "commit": "5db873d4af9f6bf57748884bfd4cbccebd4e6863" },
|
||||
"better-escape.nvim": { "branch": "master", "commit": "199dcc2643dec5d8dbdab4ec672cf405224dcb3b" },
|
||||
"blink.cmp": { "branch": "main", "commit": "9bcb14b43852a6f2bfd5ac9ef29cb5cf09b1b39b" },
|
||||
"blink.compat": { "branch": "main", "commit": "2ed6d9a28b07fa6f3bface818470605f8896408c" },
|
||||
"cmp-dap": { "branch": "master", "commit": "ea92773e84c0ad3288c3bc5e452ac91559669087" },
|
||||
"friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" },
|
||||
"gitsigns.nvim": { "branch": "main", "commit": "7010000889bfb6c26065e0b0f7f1e6aa9163edd9" },
|
||||
"guess-indent.nvim": { "branch": "main", "commit": "84a4987ff36798c2fc1169cbaff67960aed9776f" },
|
||||
"heirline.nvim": { "branch": "master", "commit": "fae936abb5e0345b85c3a03ecf38525b0828b992" },
|
||||
"lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" },
|
||||
"lazydev.nvim": { "branch": "main", "commit": "f59bd14a852ca43db38e3662395354cb2a9b13e0" },
|
||||
"mason-lspconfig.nvim": { "branch": "main", "commit": "1a31f824b9cd5bc6f342fc29e9a53b60d74af245" },
|
||||
"mason-null-ls.nvim": { "branch": "main", "commit": "2b8433f76598397fcc97318d410e0c4f7a4bea6a" },
|
||||
"mason-nvim-dap.nvim": { "branch": "main", "commit": "4c2cdc69d69fe00c15ae8648f7e954d99e5de3ea" },
|
||||
"mason-tool-installer.nvim": { "branch": "main", "commit": "517ef5994ef9d6b738322664d5fdd948f0fdeb46" },
|
||||
"mason.nvim": { "branch": "main", "commit": "7f265cd6ae56cecdd0aa50c8c73fc593b0604801" },
|
||||
"mini.icons": { "branch": "main", "commit": "397ed3807e96b59709ef3292f0a3e253d5c1dc0a" },
|
||||
"neo-tree.nvim": { "branch": "main", "commit": "f481de16a0eb59c985abac8985e3f2e2f75b4875" },
|
||||
"neoconf.nvim": { "branch": "main", "commit": "907a1fe4e346aab2989af6848d7d697098506c5e" },
|
||||
"none-ls.nvim": { "branch": "main", "commit": "db2a48b79cfcdab8baa5d3f37f21c78b6705c62e" },
|
||||
"nui.nvim": { "branch": "main", "commit": "f535005e6ad1016383f24e39559833759453564e" },
|
||||
"nvim-autopairs": { "branch": "master", "commit": "23320e75953ac82e559c610bec5a90d9c6dfa743" },
|
||||
"nvim-dap": { "branch": "master", "commit": "14fe46ae16eb272629144a93f7738f5279665a4f" },
|
||||
"nvim-dap-ui": { "branch": "master", "commit": "73a26abf4941aa27da59820fd6b028ebcdbcf932" },
|
||||
"nvim-highlight-colors": { "branch": "main", "commit": "b42a5ccec7457b44e89f7ed3b3afb1b375bb2093" },
|
||||
"nvim-lspconfig": { "branch": "master", "commit": "fa2662510d30b06168b6e2e6915518decde6bbac" },
|
||||
"nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" },
|
||||
"nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
|
||||
"nvim-treesitter-textobjects": { "branch": "master", "commit": "89ebe73cd2836db80a22d9748999ace0241917a5" },
|
||||
"nvim-ts-autotag": { "branch": "main", "commit": "a1d526af391f6aebb25a8795cbc05351ed3620b5" },
|
||||
"nvim-ts-context-commentstring": { "branch": "main", "commit": "1b212c2eee76d787bbea6aa5e92a2b534e7b4f8f" },
|
||||
"nvim-ufo": { "branch": "main", "commit": "61463090a4f55f5d080236ea62f09d1cd8976ff3" },
|
||||
"nvim-window-picker": { "branch": "main", "commit": "6382540b2ae5de6c793d4aa2e3fe6dbb518505ec" },
|
||||
"plenary.nvim": { "branch": "master", "commit": "857c5ac632080dba10aae49dba902ce3abf91b35" },
|
||||
"promise-async": { "branch": "main", "commit": "38a4575da9497326badd3995e768b4ccf0bb153e" },
|
||||
"resession.nvim": { "branch": "master", "commit": "cc819b0489938d03e4f3532a583354f0287c015b" },
|
||||
"smart-splits.nvim": { "branch": "master", "commit": "ddb23c1a1cf1507bda487cda7f6e4690965ef9f5" },
|
||||
"snacks.nvim": { "branch": "main", "commit": "5eac729fa290248acfe10916d92a5ed5e5c0f9ed" },
|
||||
"todo-comments.nvim": { "branch": "main", "commit": "304a8d204ee787d2544d8bc23cd38d2f929e7cc5" },
|
||||
"toggleterm.nvim": { "branch": "main", "commit": "50ea089fc548917cc3cc16b46a8211833b9e3c7c" },
|
||||
"vim-illuminate": { "branch": "master", "commit": "0d1e93684da00ab7c057410fecfc24f434698898" },
|
||||
"which-key.nvim": { "branch": "main", "commit": "fcbf4eea17cb299c02557d576f0d568878e354a4" }
|
||||
}
|
||||
+76
-7
@@ -1,12 +1,81 @@
|
||||
if true then return {} end -- WARN: REMOVE THIS LINE TO ACTIVATE THIS FILE
|
||||
|
||||
-- AstroCommunity: import any community modules here
|
||||
-- We import this file in `lazy_setup.lua` before the `plugins/` folder.
|
||||
-- This guarantees that the specs are processed before any user plugins.
|
||||
|
||||
---@type LazySpec
|
||||
return {
|
||||
"AstroNvim/astrocommunity",
|
||||
{ import = "astrocommunity.pack.lua" },
|
||||
-- import/override with your plugins folder
|
||||
--- @alias FrameworkModuleSpec { import: string }
|
||||
|
||||
--- @alias FrameworkModules table<string, FrameworkModuleSpec[]>
|
||||
|
||||
-- Framework-specific community module configurations
|
||||
--- @type FrameworkModules
|
||||
local FRAMEWORK_COMMUNITY_MODULES = {
|
||||
-- Base Lua pack - always included
|
||||
lua = {
|
||||
{ import = "astrocommunity.pack.lua" },
|
||||
},
|
||||
|
||||
-- Vue.js framework modules
|
||||
vue = {
|
||||
{ import = "astrocommunity.pack.vue" },
|
||||
},
|
||||
}
|
||||
|
||||
--- Retrieves the appropriate community modules based on the current framework environment
|
||||
--- @return LazySpec[] List of community modules to import for the detected framework
|
||||
local function get_framework_modules()
|
||||
--- @type string|nil
|
||||
local current_framework = os.getenv "FRAMEWORK"
|
||||
--- @type LazySpec[]
|
||||
local modules = {}
|
||||
|
||||
-- Always include base Lua pack
|
||||
for _, module in ipairs(FRAMEWORK_COMMUNITY_MODULES.lua) do
|
||||
table.insert(modules, module)
|
||||
end
|
||||
|
||||
-- If framework is not set or empty string, use only base modules
|
||||
if not current_framework or current_framework == "" then return modules end
|
||||
|
||||
-- Check if framework is valid (vue or python)
|
||||
if current_framework ~= "vue" and current_framework ~= "python" then
|
||||
error("Invalid framework: '" .. current_framework .. "'. Valid frameworks are: vue, python")
|
||||
end
|
||||
|
||||
-- Add framework-specific modules if framework is valid
|
||||
if FRAMEWORK_COMMUNITY_MODULES[current_framework] then
|
||||
for _, module in ipairs(FRAMEWORK_COMMUNITY_MODULES[current_framework]) do
|
||||
table.insert(modules, module)
|
||||
end
|
||||
end
|
||||
|
||||
return modules
|
||||
end
|
||||
|
||||
--- Checks if third-party AI assistant is enabled and adds Avante-nvim if true
|
||||
--- @return LazySpec|nil Avante-nvim module if AI is enabled, nil otherwise
|
||||
local function get_ai_modules()
|
||||
-- Check if third-party AI assistant is enabled
|
||||
local ai_enabled = os.getenv "THIRD_PARTY_AI_ASSISTANT"
|
||||
if ai_enabled and ai_enabled:lower() == "true" then return { import = "astrocommunity.completion.avante-nvim" } end
|
||||
return nil
|
||||
end
|
||||
|
||||
---@type LazySpec[]
|
||||
local modules = {
|
||||
-- Base AstroCommunity plugin
|
||||
"AstroNvim/astrocommunity",
|
||||
}
|
||||
|
||||
-- Add framework-specific modules
|
||||
local framework_modules = get_framework_modules()
|
||||
for _, module in ipairs(framework_modules) do
|
||||
table.insert(modules, module)
|
||||
end
|
||||
|
||||
-- Add AI modules if enabled
|
||||
local ai_module = get_ai_modules()
|
||||
if ai_module then
|
||||
table.insert(modules, ai_module)
|
||||
end
|
||||
|
||||
return modules
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
require("lazy").setup({
|
||||
{
|
||||
"AstroNvim/AstroNvim",
|
||||
version = "5.3.4", -- Remove version tracking to elect for nightly AstroNvim
|
||||
version = "5.3.12", -- Remove version tracking to elect for nightly AstroNvim
|
||||
import = "astronvim.plugins",
|
||||
opts = { -- AstroNvim options must be set here with the `import` key
|
||||
mapleader = " ", -- This ensures the leader key must be configured before Lazy is set up
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
if true then return {} end -- WARN: REMOVE THIS LINE TO ACTIVATE THIS FILE
|
||||
|
||||
-- AstroLSP allows you to customize the features in AstroNvim's LSP configuration engine
|
||||
-- Configuration documentation can be found with `:h astrolsp`
|
||||
-- NOTE: We highly recommend setting up the Lua Language Server (`:LspInstall lua_ls`)
|
||||
@@ -31,8 +29,11 @@ return {
|
||||
disabled = { -- disable formatting capabilities for the listed language servers
|
||||
-- disable lua_ls formatting capability if you want to use StyLua to format your lua code
|
||||
-- "lua_ls",
|
||||
"volar",
|
||||
"vtsls",
|
||||
"ts_ls",
|
||||
},
|
||||
timeout_ms = 1000, -- default format timeout
|
||||
timeout_ms = 7000, -- default format timeout
|
||||
-- filter = function(client) -- fully override the default formatting function
|
||||
-- return true
|
||||
-- end
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
-- Configuration module for avante.nvim plugin with DeepSeek API support
|
||||
-- Returns configuration only if THIRD_PARTY_AI_ASSISTANT environment variable is set
|
||||
|
||||
-- Check for the required environment variable containing the API key
|
||||
-- If the key is not set, returns an empty table and the plugin won't load
|
||||
local ai_enabled = os.getenv "THIRD_PARTY_AI_ASSISTANT"
|
||||
if not ai_enabled or ai_enabled:lower() ~= "true" then return {} end
|
||||
|
||||
-- Main plugin configuration object
|
||||
---@type LazyPluginSpec[]
|
||||
return {
|
||||
{
|
||||
-- Plugin identifier in GitHub repository
|
||||
"yetone/avante.nvim",
|
||||
-- Plugin version for compatibility assurance
|
||||
version = "0.0.27",
|
||||
-- Plugin configuration options
|
||||
-- Remove the type annotation if avante.Config is undefined
|
||||
opts = {
|
||||
provider = "deepseek_safe",
|
||||
|
||||
behaviour = {
|
||||
auto_approve_tool_permissions = true,
|
||||
},
|
||||
|
||||
vendors = {
|
||||
deepseek_safe = {
|
||||
__inherited_from = "openai",
|
||||
api_key_name = "DEEPSEEK_API_KEY",
|
||||
endpoint = "https://api.deepseek.com",
|
||||
model = "deepseek-chat",
|
||||
timeout = 120000,
|
||||
max_tokens = 8192,
|
||||
extra_request_body = {
|
||||
temperature = 0,
|
||||
max_tokens = 8192,
|
||||
},
|
||||
|
||||
-- parse_curl_args = function(opts, code_opts)
|
||||
-- local log_file = io.open("/tmp/avante_debug.log", "a")
|
||||
--
|
||||
-- -- Helper function to extract text from content
|
||||
-- local function get_content_text(content)
|
||||
-- if type(content) == "string" then
|
||||
-- return content
|
||||
-- elseif type(content) == "table" then
|
||||
-- -- Content can be array of {type="text", text="..."}
|
||||
-- if content.text then
|
||||
-- return content.text
|
||||
-- elseif content[1] and content[1].text then
|
||||
-- return content[1].text
|
||||
-- end
|
||||
-- return vim.inspect(content) -- fallback
|
||||
-- end
|
||||
-- return ""
|
||||
-- end
|
||||
--
|
||||
-- if log_file and code_opts.messages then
|
||||
-- log_file:write "\n=== NEW REQUEST ===\n"
|
||||
-- log_file:write(string.format("Total messages: %d\n", #code_opts.messages))
|
||||
--
|
||||
-- -- Check for duplicates
|
||||
-- if #code_opts.messages >= 2 then
|
||||
-- local last = code_opts.messages[#code_opts.messages]
|
||||
-- local prev = code_opts.messages[#code_opts.messages - 1]
|
||||
--
|
||||
-- local last_text = get_content_text(last.content)
|
||||
-- local prev_text = get_content_text(prev.content)
|
||||
--
|
||||
-- log_file:write(string.format("\nLast text: %s\n", last_text))
|
||||
-- log_file:write(string.format("Prev text: %s\n", prev_text))
|
||||
--
|
||||
-- if last_text == prev_text and last_text ~= "" then
|
||||
-- log_file:write "\n!!! DUPLICATE DETECTED !!!\n"
|
||||
-- log_file:close()
|
||||
-- vim.notify("Duplicate message detected! Aborting.", vim.log.levels.ERROR)
|
||||
-- return nil
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- log_file:close()
|
||||
-- end
|
||||
--
|
||||
-- local openai = require("avante.providers").openai
|
||||
-- return openai.parse_curl_args(opts, code_opts)
|
||||
-- end,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
init.lua
|
||||
@@ -1,16 +0,0 @@
|
||||
-- config.lua
|
||||
local config = {
|
||||
-- lspconfig
|
||||
"eslint-lsp",
|
||||
"stylelint-lsp",
|
||||
"tailwindcss-language-server",
|
||||
"typescript-language-server",
|
||||
-- "vue-language-server",
|
||||
{ "vue-language-server", version = "1.8.27" },
|
||||
|
||||
-- null_ls
|
||||
"stylelint",
|
||||
"prettier",
|
||||
}
|
||||
|
||||
return config
|
||||
@@ -1,15 +0,0 @@
|
||||
local vue = require "plugins.mason.vue"
|
||||
-- Customize Mason
|
||||
|
||||
---@type LazySpec
|
||||
return {
|
||||
-- use mason-tool-installer for automatically installing Mason packages
|
||||
{
|
||||
"WhoIsSethDaniel/mason-tool-installer.nvim",
|
||||
-- overrides `require("mason-tool-installer").setup(...)`
|
||||
opts = {
|
||||
-- Make sure to use the names found in `:Mason`
|
||||
ensure_installed = vue,
|
||||
},
|
||||
},
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Path to the branch_time_calculator.py script
|
||||
CALCULATOR_PATH="$HOME/.config/nvim/lua/plugins/pendulum/branch_time_calculator.py"
|
||||
|
||||
# Check if the calculator script exists
|
||||
if [ ! -f "$CALCULATOR_PATH" ]; then
|
||||
echo "Error: The branch_time_calculator.py script was not found at $CALCULATOR_PATH."
|
||||
echo "Please ensure the 'pendulum' plugin is installed in your Neovim configuration."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute the calculator script
|
||||
python3 "$CALCULATOR_PATH" "$@"
|
||||
@@ -0,0 +1,182 @@
|
||||
import csv
|
||||
import datetime
|
||||
import os
|
||||
import subprocess
|
||||
import argparse
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
|
||||
class BranchTimeCalculator:
|
||||
"""
|
||||
A class to calculate time spent on a Git branch with exact project matching.
|
||||
Handles lowercase 'true' for active status and flexible CSV parsing.
|
||||
"""
|
||||
|
||||
def __init__(self, csv_file: Optional[str] = None, target_branch: Optional[str] = None, debug: bool = False):
|
||||
"""
|
||||
Initialize the calculator with optional CSV file, target branch and debug mode.
|
||||
|
||||
Args:
|
||||
csv_file (Optional[str]): Path to CSV log file. Defaults to ~/pendulum-log.csv.
|
||||
target_branch (Optional[str]): Name of the target branch. Defaults to current branch.
|
||||
debug (bool): If True, prints debug information. Defaults to False.
|
||||
"""
|
||||
self.csv_file = csv_file or os.path.expanduser("~/pendulum-log.csv")
|
||||
self.target_branch = target_branch
|
||||
self.debug = debug
|
||||
self.current_project = self._get_project_name()
|
||||
|
||||
def _get_project_name(self) -> str:
|
||||
"""
|
||||
Get the project name from Git config or fall back to directory name.
|
||||
|
||||
Returns:
|
||||
str: The project name.
|
||||
"""
|
||||
try:
|
||||
return subprocess.check_output(
|
||||
["git", "config", "--get", "remote.origin.url"],
|
||||
stderr=subprocess.DEVNULL,
|
||||
text=True
|
||||
).strip().split('/')[-1].replace('.git', '')
|
||||
except subprocess.CalledProcessError:
|
||||
return os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
def _get_current_branch(self) -> Optional[str]:
|
||||
"""
|
||||
Get the current Git branch name.
|
||||
|
||||
Returns:
|
||||
Optional[str]: The branch name or None if not in a Git repo.
|
||||
"""
|
||||
try:
|
||||
return subprocess.check_output(
|
||||
["git", "branch", "--show-current"],
|
||||
stderr=subprocess.DEVNULL,
|
||||
text=True
|
||||
).strip()
|
||||
except subprocess.CalledProcessError:
|
||||
print("Error: Not a Git repository or branch not found.")
|
||||
return None
|
||||
|
||||
def _parse_log_entry(self, row: List[str]) -> Dict[str, str]:
|
||||
"""
|
||||
Parse a CSV row into a log entry dictionary.
|
||||
|
||||
Args:
|
||||
row (List[str]): A row from the CSV log file.
|
||||
|
||||
Returns:
|
||||
Dict[str, str]: A dictionary representing the log entry.
|
||||
"""
|
||||
return {
|
||||
'active': row[0].lower().strip(),
|
||||
'branch': row[1].strip(),
|
||||
'directory': row[2].strip(),
|
||||
'file': row[3].strip(),
|
||||
'filetype': row[4].strip(),
|
||||
'project': row[5].strip(),
|
||||
'time': row[6].strip()
|
||||
}
|
||||
|
||||
def _calculate_time_deltas(self, log_entries: List[Dict[str, str]]) -> Dict[str, datetime.timedelta]:
|
||||
"""
|
||||
Calculate total and active time from log entries.
|
||||
|
||||
Args:
|
||||
log_entries (List[Dict[str, str]]): List of parsed log entries.
|
||||
|
||||
Returns:
|
||||
Dict[str, datetime.timedelta]: A dictionary with 'total_time' and 'active_time'.
|
||||
"""
|
||||
total_time = datetime.timedelta()
|
||||
active_time = datetime.timedelta()
|
||||
prev_time = None
|
||||
|
||||
for entry in log_entries:
|
||||
try:
|
||||
current_time = datetime.datetime.strptime(entry['time'], '%Y-%m-%d %H:%M:%S')
|
||||
except ValueError as e:
|
||||
print(f"[ERROR] Time parse failed: {entry['time']}. Error: {e}")
|
||||
continue
|
||||
|
||||
if prev_time is not None:
|
||||
time_diff = current_time - prev_time
|
||||
total_time += time_diff
|
||||
if entry['active'] == 'true':
|
||||
active_time += time_diff
|
||||
|
||||
prev_time = current_time
|
||||
|
||||
return {'total_time': total_time, 'active_time': active_time}
|
||||
|
||||
def calculate(self) -> Optional[Dict[str, any]]:
|
||||
"""
|
||||
Calculate time spent on the target branch.
|
||||
|
||||
Returns:
|
||||
Optional[Dict[str, any]]: A dictionary with branch, project, total_time, active_time, and active_percentage.
|
||||
Returns None if calculation fails.
|
||||
"""
|
||||
if self.target_branch is None:
|
||||
self.target_branch = self._get_current_branch()
|
||||
if self.target_branch is None:
|
||||
return None
|
||||
|
||||
log_entries = []
|
||||
try:
|
||||
with open(self.csv_file, mode='r') as file:
|
||||
for line in file:
|
||||
row = list(csv.reader([line.strip()], delimiter=',', quotechar='"'))[0]
|
||||
if len(row) != 7:
|
||||
if self.debug:
|
||||
print(f"[DEBUG] Skipping malformed line: {line}")
|
||||
continue
|
||||
|
||||
log_entry = self._parse_log_entry(row)
|
||||
if log_entry['branch'] == self.target_branch and log_entry['project'] == self.current_project:
|
||||
log_entries.append(log_entry)
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Error: Log file not found at {self.csv_file}")
|
||||
return None
|
||||
|
||||
time_deltas = self._calculate_time_deltas(log_entries)
|
||||
total_seconds = time_deltas['total_time'].total_seconds()
|
||||
active_percentage = (time_deltas['active_time'].total_seconds() / total_seconds) * 100 if total_seconds > 0 else 0
|
||||
|
||||
if self.debug:
|
||||
print(f"\nTime spent on branch '{self.target_branch}' in project '{self.current_project}':")
|
||||
print(f"- Total time: {time_deltas['total_time']}")
|
||||
print(f"- Active time: {time_deltas['active_time']}")
|
||||
print(f"- Active percentage: {active_percentage:.2f}%")
|
||||
else:
|
||||
print(f"In project '{self.current_project}' on branch '{self.target_branch}' you spent actively working: {time_deltas['active_time']}")
|
||||
|
||||
return {
|
||||
'branch': self.target_branch,
|
||||
'project': self.current_project,
|
||||
'total_time': time_deltas['total_time'],
|
||||
'active_time': time_deltas['active_time'],
|
||||
'active_percentage': active_percentage
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to parse arguments and run the calculator."""
|
||||
parser = argparse.ArgumentParser(description='Calculate branch activity time.')
|
||||
parser.add_argument('--csv-file', type=str, help='Path to CSV log (default: ~/pendulum-log.csv)')
|
||||
parser.add_argument('--branch', type=str, help='Branch name (default: current)')
|
||||
parser.add_argument('--debug', action='store_true', help='Enable debug output')
|
||||
args = parser.parse_args()
|
||||
|
||||
calculator = BranchTimeCalculator(args.csv_file, args.branch, args.debug)
|
||||
result = calculator.calculate()
|
||||
|
||||
if not result:
|
||||
print("\nCalculation failed - check debug output above.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---@type LazySpec
|
||||
return {
|
||||
"ptdewey/pendulum-nvim",
|
||||
version = "1.1.0",
|
||||
config = function()
|
||||
require("pendulum").setup {
|
||||
time_zone = "Europe/Moscow",
|
||||
gen_reports = false,
|
||||
}
|
||||
end,
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
if true then return end -- WARN: REMOVE THIS LINE TO ACTIVATE THIS FILE
|
||||
|
||||
-- This will run last in the setup process.
|
||||
-- This is just pure lua so anything that doesn't
|
||||
-- fit in the normal config locations above can go here
|
||||
@@ -0,0 +1,154 @@
|
||||
--- Mason package installation utilities for Neovim.
|
||||
--- This module provides functions for installing Mason packages based on framework environment.
|
||||
|
||||
--- @alias FrameworkName "python"|"vue"|string
|
||||
|
||||
--- @class FrameworkTools
|
||||
--- @field python string[] Python development tools and LSP servers including formatters, linters, and type checkers
|
||||
--- @field vue string[] Vue.js development tools and LSP servers including JavaScript/TypeScript tools and CSS utilities
|
||||
|
||||
--- Framework-specific tool configurations
|
||||
--- Maps framework names to their respective tool lists
|
||||
--- @type FrameworkTools
|
||||
local FRAMEWORK_TOOLS = {
|
||||
python = {
|
||||
"black",
|
||||
"python-lsp-server",
|
||||
"mypy",
|
||||
"pylint",
|
||||
"flake8",
|
||||
"pylama",
|
||||
"bandit",
|
||||
"pydocstyle",
|
||||
"pyproject-flake8",
|
||||
"pyproject-fmt",
|
||||
"reorder-python-imports",
|
||||
},
|
||||
vue = {
|
||||
"eslint-lsp",
|
||||
"stylelint-lsp",
|
||||
"tailwindcss-language-server",
|
||||
"typescript-language-server",
|
||||
"stylelint",
|
||||
"prettier",
|
||||
},
|
||||
}
|
||||
|
||||
--- Retrieves the appropriate tool set based on the current framework environment.
|
||||
--- This function checks the FRAMEWORK environment variable and returns the corresponding
|
||||
--- tool list from FRAMEWORK_TOOLS. If no framework is set or the framework is not recognized,
|
||||
--- returns an empty table.
|
||||
--- @return string[] tools List of tools to install for the detected framework, or empty table if no framework is set
|
||||
local function get_framework_tools()
|
||||
local current_framework = os.getenv "FRAMEWORK"
|
||||
|
||||
if current_framework then
|
||||
local tools = FRAMEWORK_TOOLS[current_framework]
|
||||
return tools or {}
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
--- Validates if a package name is safe to install.
|
||||
--- This function performs basic security validation to prevent command injection
|
||||
--- and ensures package names follow expected patterns.
|
||||
--- @param package_name string The package name to validate
|
||||
--- @return boolean is_valid True if the package name is valid, false otherwise
|
||||
local function is_valid_package_name(package_name)
|
||||
-- Basic validation: package names should only contain alphanumeric characters, hyphens, and dots
|
||||
-- This prevents command injection attacks
|
||||
if type(package_name) ~= "string" or package_name == "" then return false end
|
||||
|
||||
-- Additional security: check for potentially dangerous patterns
|
||||
local dangerous_patterns = {
|
||||
"%.%.%/", -- Path traversal
|
||||
"%;", -- Command separator
|
||||
"%|", -- Pipe
|
||||
"%&", -- Background process
|
||||
"%`", -- Command substitution
|
||||
"%$", -- Variable expansion
|
||||
"%!", -- History expansion
|
||||
}
|
||||
|
||||
for _, pattern in ipairs(dangerous_patterns) do
|
||||
if string.match(package_name, pattern) then return false end
|
||||
end
|
||||
|
||||
-- Check for valid characters: alphanumeric, hyphen, dot, underscore
|
||||
local valid_pattern = "^[%w%-%.%_]+$"
|
||||
return string.match(package_name, valid_pattern) ~= nil
|
||||
end
|
||||
|
||||
--- Checks if Mason is available and ready for package installation.
|
||||
--- @return boolean is_available True if Mason is available, false otherwise
|
||||
local function is_mason_available()
|
||||
local mason_ok, _ = pcall(require, "mason")
|
||||
return mason_ok
|
||||
end
|
||||
|
||||
--- Installs Mason packages based on the current framework environment.
|
||||
--- This function retrieves the appropriate tool set and installs them one by one
|
||||
--- to handle individual failures gracefully. Each package installation is wrapped
|
||||
--- in a protected call to prevent one failure from stopping the entire process.
|
||||
--- @return nil
|
||||
function InstallMyMasonPackages()
|
||||
-- Check if Mason is available first
|
||||
if not is_mason_available() then
|
||||
vim.notify("Mason is not available. Please install Mason first.", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local packages = get_framework_tools()
|
||||
|
||||
if #packages > 0 then
|
||||
local installed_count = 0
|
||||
local failed_count = 0
|
||||
|
||||
-- Install packages one by one to handle individual failures
|
||||
for _, package in ipairs(packages) do
|
||||
-- Validate package name for security
|
||||
if not is_valid_package_name(package) then
|
||||
vim.notify("Skipping invalid package name: " .. package, vim.log.levels.WARN)
|
||||
failed_count = failed_count + 1
|
||||
else
|
||||
local success, result = pcall(function() vim.cmd("MasonInstall " .. package) end)
|
||||
|
||||
if success then
|
||||
installed_count = installed_count + 1
|
||||
vim.notify("Successfully installed: " .. package, vim.log.levels.INFO)
|
||||
else
|
||||
failed_count = failed_count + 1
|
||||
vim.notify("Failed to install " .. package .. ": " .. tostring(result), vim.log.levels.WARN)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Provide summary
|
||||
if failed_count == 0 then
|
||||
vim.notify(
|
||||
"Framework-specific packages installation completed successfully. Installed: " .. installed_count .. " packages",
|
||||
vim.log.levels.INFO
|
||||
)
|
||||
else
|
||||
vim.notify(
|
||||
"Framework-specific packages installation completed with "
|
||||
.. failed_count
|
||||
.. " failures. Successfully installed: "
|
||||
.. installed_count
|
||||
.. " packages",
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
end
|
||||
else
|
||||
vim.notify("No framework detected or no packages to install", vim.log.levels.INFO)
|
||||
end
|
||||
end
|
||||
|
||||
-- Module exports
|
||||
return {
|
||||
FRAMEWORK_TOOLS = FRAMEWORK_TOOLS,
|
||||
get_framework_tools = get_framework_tools,
|
||||
InstallMyMasonPackages = InstallMyMasonPackages,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
--- @meta
|
||||
|
||||
--- Framework-specific tool configurations and installation utilities for Neovim.
|
||||
--- This module provides automatic installation of language servers and tools
|
||||
--- based on the current development framework environment.
|
||||
--- It reads the FRAMEWORK environment variable to determine which tools to install.
|
||||
|
||||
-- Import Mason utilities from separate module
|
||||
local mason = require "polish.framework_mason_packages"
|
||||
|
||||
-- Create user command for Mason installation
|
||||
vim.api.nvim_create_user_command(
|
||||
"MasonInstallForFramework", -- Command name
|
||||
mason.InstallMyMasonPackages, -- Function to call
|
||||
{ nargs = 0 } -- Command takes no arguments
|
||||
)
|
||||
|
||||
-- Module exports
|
||||
return {
|
||||
FRAMEWORK_TOOLS = mason.FRAMEWORK_TOOLS,
|
||||
get_framework_tools = mason.get_framework_tools,
|
||||
InstallMyMasonPackages = mason.InstallMyMasonPackages,
|
||||
}
|
||||
Reference in New Issue
Block a user