ptdewey/pendulum-nvim

github github
utility
stars 86
issues 2
subscribers 2
forks 4
CREATED

2024-04-11

UPDATED

15 days ago


Pendulum-nvim

Pendulum is a Neovim plugin designed for tracking time spent on projects within Neovim. It logs various events like entering and leaving buffers and idle times into a CSV file, making it easy to analyze your coding activity over time.

Pendulum also includes a user command that aggregates log information into a popup report viewable within your editor

Pendulum Metrics View

Pendulum Active Hours View

Motivation

Pendulum was created to offer a privacy-focused alternative to cloud-based time tracking tools, addressing concerns about data security and ownership. This "local-first" tool ensures all data stays on the user's machine, providing full control and customization without requiring internet access. It's designed for developers who prioritize privacy and autonomy but are curious about how they spend their time.

What it Does

  • Automatic Time Tracking: Logs time spent in each file along with the workding directory, file type, project name, and git branch if available.
  • Activity Detection: Detects user activity based on cursor movements (on a timer) and buffer switches.
  • Customizable Timeout: Configurable timeout to define user inactivity.
  • Event Logging: Tracks buffer events and idle periods, writing these to a CSV log for later analysis.
  • Report Generation: Generate reports from the log file to quickly view how time was spent on various projects (requires Go installed).

Installation

Install Pendulum using your favorite package manager:

With Report Generation (Requires Go)

With lazy.nvim

{
    "ptdewey/pendulum-nvim",
    config = function()
        require("pendulum").setup()
    end,
}

Without Report Generation

With lazy.nvim

{
    "ptdewey/pendulum-nvim",
    config = function()
        require("pendulum").setup({
            gen_reports = false,
        })
    end,
}

Configuration

Pendulum can be customized with several options. Here is a table with configurable options:

Option Description Default
log_file Path to the CSV file where logs should be written $HOME/pendulum-log.csv
timeout_len Length of time in seconds to determine inactivity 180
timer_len Interval in seconds at which to check activity 120
gen_reports Generate reports from the log file true
top_n Number of top entries to include in the report 5
hours_n Number of entries to show in active hours report 10
time_format Use 12/24 hour time format for active hours report (possible values: 12h, 24h) 12h
time_zone Time zone for use in active hour calculations (format: America/New_York) UTC
report_section_excludes Additional filters to be applied to each report section {}
report_excludes Show/Hide report sections. e.g branch, directory, file, filetype, project {}

Default configuration

require("pendulum").setup({
    log_file = vim.env.HOME .. "/pendulum-log.csv",
    timeout_len = 180,
    timer_len = 120,
    gen_reports = true,
    top_n = 5,
    hours_n = 10,
    time_format = "12h",
    time_zone = "UTC", -- Format "America/New_York"
    report_excludes = {
        branch = {},
        directory = {},
        file = {},
        filetype = {},
        project = {},
    },
    report_section_excludes = {},
})

Example configuration with custom options: (Note: this is not the recommended configuration, but just shows potential options)

require('pendulum').setup({
    log_file = vim.fn.expand("$HOME/Documents/my_custom_log.csv"),
    timeout_len = 300,  -- 5 minutes
    timer_len = 60,     -- 1 minute
    gen_reports = true, -- Enable report generation (requires Go)
    top_n = 10,         -- Include top 10 entries in the report
    hours_n = 10,
    time_format = "12h",
    time_zone = "America/New_York",
    report_section_excludes = {
        "branch",       -- Hide `branch` section of the report
        -- Other options includes:
        -- "directory",
        -- "filetype",
        -- "file",
        -- "project",
    },
    report_excludes = {
        filetype = {
            -- This table controls what to be excluded from `filetype` section
            "neo-tree", -- Exclude neo-tree filetype
        },
        file = {
            -- This table controls what to be excluded from `file` section
            "test.py",  -- Exclude any test.py
            ".*.go",    -- Exclude all Go files
        }
        project = {
            -- This table controls what to be excluded from `project` section
            "unknown_project" -- Exclude unknown (non-git) projects
        },
        directory = {
            -- This table controls what to be excluded from `directory` section
        },
        branch = {
            -- This table controls what to be excluded from `branch` section
        },
    },
})

Note: You can use regex to express the matching patterns within report_excludes.

Usage

Once configured, Pendulum runs automatically in the background. It logs each specified event into the CSV file, which includes timestamps, file names, project names (from Git), and activity states.

The CSV log file will have the columns: time, active, file, filetype, cwd, project, and branch.

Report Generation

Pendulum can generate detailed reports from the log file. To use this feature, you need to have Go installed on your system. The report includes the top entries based on the time spent on various projects.

To rebuild the Pendulum binary and generate reports, use the following commands:

:PendulumRebuild
:Pendulum
:PendulumHours

The :PendulumRebuild command recompiles the Go binary, and the :Pendulum command generates the report based on the current log file. I recommend rebuilding the binary after the plugin is updated.

The :Pendulum command generates and shows the metrics view (i.e. time spent per branch, project, filetype, etc.). Report generation will take longer as the size of your log file increases.

The :PendulumHours command generates and shows the active hours view, which shows which times of day you are most active (and time spent).

If you do not want to install Go, report generation can be disabled by changing the gen_reports option to false. Disabling reports will cause the Pendulum, PendulumHours, and PendulumRebuild commands to not be created since they are exclusively used for the reports feature.

config = function()
    require("pendulum").setup({
        -- disable report generations (avoids Go dependency)
        gen_reports = false,
    })
end,

The metrics report contents are customizable and section items or entire sections can be excluded from the report if desired. (See report_excludes and report_section_excludes options in setup)

Future Ideas

These are some potential future ideas that would make for welcome contributions for anyone interested.

  • Logging to SQLite database (optionally)
  • Telescope integration
  • Get stats for specified project, filetype, etc. (Could work well with Telescope)
  • Nicer looking popup with custom highlight groups
  • Alternative version of popup that uses a terminal buffer and bubbletea (using the table component)