1- local Job = require " plenary.job "
1+ --- @class Wrapped.Core.Git
22local M = {}
3+ local Job = require " plenary.job"
34
5+ --- @return string path
46local function get_path () return require (" wrapped" ).config .path end
57
8+ --- @param args string[]
9+ --- @return string[] result
610local function exec_git (args )
711 local job = Job :new {
812 command = " git" ,
@@ -13,72 +17,69 @@ local function exec_git(args)
1317 return job :result ()
1418end
1519
16- --- @return string[]
20+ --- @return string[] commits
1721function M .get_commits ()
1822 local all = exec_git { " log" , " --format=%s" }
1923 if # all <= 5 then return all end
2024
21- local random_commits = {}
22- local indices = {}
25+ local random_commits = {} --- @type string[]
26+ local indices = {} --- @type integer[]
2327 while # indices < 5 do
2428 local idx = math.random (1 , # all )
25- if not vim .tbl_contains (indices , idx ) then
29+ if not vim .list_contains (indices , idx ) then
2630 table.insert (indices , idx )
2731 table.insert (random_commits , all [idx ])
2832 end
2933 end
3034 return random_commits
3135end
3236
33- --- @return string
37+ --- @return string total
3438function M .get_total_count ()
3539 return exec_git ({ " rev-list" , " --count" , " HEAD" })[1 ] or " 0"
3640end
3741
38- --- @return string
42+ --- @return string first_date
3943function M .get_first_commit_date ()
4044 return exec_git ({ " log" , " --reverse" , " --format=%ad" , " --date=short" })[1 ]
4145 or " Unknown"
4246end
4347
4448-- converts seconds to human-readable
49+ --- @param secs integer
50+ --- @return string ago
4551local function format_ago (secs )
4652 local days = math.floor (secs / 86400 )
47- if days >= 365 then return string.format (" %.1f years ago" , days / 365 ) end
53+ if days >= 365 then return (" %.1f years ago" ): format ( days / 365 ) end
4854 if days >= 30 then return math.floor (days / 30 ) .. " months ago" end
4955 if days >= 1 then return days .. " days ago" end
50- local hours = math.floor (secs / 3600 )
51- if hours >= 1 then return hours .. " hours ago" end
56+ if secs >= 3600 then return math.floor (secs / 3600 ) .. " hours ago" end
5257 return math.floor (secs / 60 ) .. " minutes ago"
5358end
5459
55- --- @return Wrapped.ConfigStats
60+ --- @return Wrapped.ConfigStats stats
5661function M .get_config_stats ()
5762 local dates = exec_git { " log" , " --format=%ad" , " --date=short" }
58- local unique = {}
63+ local unique = {} --- @type table<string , boolean>
5964 for _ , d in ipairs (dates ) do
6065 unique [d ] = true
6166 end
6267
6368 -- sort unique dates
64- local sorted = {}
69+ local sorted = {} --- @type string[]
6570 for d in pairs (unique ) do
6671 table.insert (sorted , d )
6772 end
6873 table.sort (sorted )
6974
7075 -- longest consecutive day streak
71- local max_streak , cur_streak = 1 , 1
76+ local max_streak , cur_streak = 1 , 1 --- @type integer , integer
7277 for i = 2 , # sorted do
73- local y , m , d = sorted [i ]:match " (%d+)-(%d+)-(%d+)"
74- local py , pm , pd = sorted [i - 1 ]:match " (%d+)-(%d+)-(%d+)"
78+ local y , m , d = sorted [i ]:match " (%d+)-(%d+)-(%d+)" --- @type string , string , string
79+ local py , pm , pd = sorted [i - 1 ]:match " (%d+)-(%d+)-(%d+)" --- @type string , string , string
7580 local t1 = os.time { year = y , month = m , day = d }
7681 local t0 = os.time { year = py , month = pm , day = pd }
77- if math.abs (t1 - t0 ) <= 86400 then
78- cur_streak = cur_streak + 1
79- else
80- cur_streak = 1
81- end
82+ cur_streak = math.abs (t1 - t0 ) <= 86400 and (cur_streak + 1 ) or 1
8283 if cur_streak > max_streak then max_streak = cur_streak end
8384 end
8485
@@ -88,27 +89,32 @@ function M.get_config_stats()
8889 local last = dates [1 ]
8990 local last_change = " Unknown"
9091 if last then
91- local y , m , d = last :match " (%d+)-(%d+)-(%d+)"
92+ local y , m , d = last :match " (%d+)-(%d+)-(%d+)" --- @type string , string , string
9293 if y and m and d then
93- last_change = format_ago (
94- now
95- - os.time { year = tonumber (y ), month = tonumber (m ), day = tonumber (d ) }
96- )
94+ last_change = format_ago (now - os.time {
95+ year = tonumber (y , 10 ),
96+ month = tonumber (m , 10 ),
97+ day = tonumber (d , 10 ),
98+ })
9799 end
98100 end
99101
100102 -- config lifetime from first commit
101103 local first = sorted [1 ]
102104 local lifetime = " Unknown"
103105 if first then
104- local y , m , d = first :match " (%d+)-(%d+)-(%d+)"
106+ local y , m , d = first :match " (%d+)-(%d+)-(%d+)" --- @type string , string , string
105107 if y and m and d then
106108 local age_days = (
107109 now
108- - os.time { year = tonumber (y ), month = tonumber (m ), day = tonumber (d ) }
110+ - os.time {
111+ year = tonumber (y , 10 ),
112+ month = tonumber (m , 10 ),
113+ day = tonumber (d , 10 ),
114+ }
109115 ) / 86400
110116 if age_days >= 365 then
111- lifetime = string.format (" %.1f years old" , age_days / 365 )
117+ lifetime = (" %.1f years old" ): format ( age_days / 365 )
112118 elseif age_days >= 30 then
113119 lifetime = math.floor (age_days / 30 ) .. " months old"
114120 else
@@ -120,11 +126,11 @@ function M.get_config_stats()
120126 local subjects = exec_git { " log" , " --format=%s" }
121127 local shortest , longest = subjects [1 ] or " " , subjects [1 ] or " "
122128 for _ , s in ipairs (subjects ) do
123- if # s < # shortest and # s > 0 then shortest = s end
124- if # s > # longest then longest = s end
129+ if s : len () < shortest : len () and s : len () > 0 then shortest = s end
130+ if s : len () > longest : len () then longest = s end
125131 end
126132
127- return {
133+ return { --- @type Wrapped.ConfigStats
128134 longest_streak = # sorted > 0 and max_streak or 0 ,
129135 last_change = last_change ,
130136 lifetime = lifetime ,
@@ -134,34 +140,31 @@ function M.get_config_stats()
134140end
135141
136142-- commit count per day for a given year, keyed as ddmmyyyy
137- --- @param year number
138- --- @return table<string , number>
143+ --- @param year integer
144+ --- @return table<string , integer> counts
139145function M .get_commit_activity (year )
140146 local dates = exec_git { " log" , " --format=%ad" , " --date=short" }
141- local yr = tostring (year )
142- local counts = {}
147+ local counts = {} --- @type table<string , integer>
143148 for _ , d in ipairs (dates ) do
144- local y , m , day = d :match " (%d+)-(%d+)-(%d+)"
145- if y == yr then
149+ local y , m , day = d :match " (%d+)-(%d+)-(%d+)" --- @type string , string , string
150+ if y == tostring ( year ) then
146151 local key = day .. m .. y
147152 counts [key ] = (counts [key ] or 0 ) + 1
148153 end
149154 end
150155 return counts
151156end
152157
153- --- @return number
158+ --- @return integer year
154159function M .get_first_commit_year ()
155- local d = M .get_first_commit_date ()
156- local y = d :match " (%d+)"
157- return tonumber (y ) or tonumber (os.date " %Y" )
160+ return tonumber (M .get_first_commit_date ():match " (%d+)" or os.date " %Y" , 10 )
158161end
159162
160163-- sample ~12 commits and get total line count at each point
161- --- @return { values : number [], labels : string[] }
164+ --- @return { values : integer [], labels : string[] } history
162165function M .get_size_history ()
163166 local log = exec_git { " log" , " --reverse" , " --format=%H %ad" , " --date=short" }
164- if # log == 0 then return { values = {}, labels = {} } end
167+ if vim . tbl_isempty ( log ) then return { values = {}, labels = {} } end
165168
166169 -- get the empty tree hash for this repo
167170 local empty = Job :new {
@@ -170,26 +173,26 @@ function M.get_size_history()
170173 cwd = get_path (),
171174 }
172175 empty :sync ()
173- local empty_tree = (empty :result ()[1 ] or " " ):match " %S+"
176+ local empty_tree = (empty :result ()[1 ] or " " ):match " %S+" --- @type string
174177
175178 -- sample ~20 evenly spaced commits
176- local samples = {}
179+ local samples = {} --- @type string[]
177180 local step = math.max (1 , math.floor (# log / 49 ))
178181 for i = 1 , # log , step do
179182 table.insert (samples , log [i ])
180183 end
181184 -- always include latest
182- if # samples > 0 and samples [# samples ] ~= log [# log ] then
185+ if not vim . tbl_isempty ( samples ) and samples [# samples ] ~= log [# log ] then
183186 table.insert (samples , log [# log ])
184187 end
185188
186- local values , labels = {}, {}
189+ local values , labels = {}, {} --- @type integer[] , string[]
187190 for _ , entry in ipairs (samples ) do
188- local hash , date = entry :match " (%S+)%s+(%S+)"
191+ local hash , date = entry :match " (%S+)%s+(%S+)" --- @type string , string
189192 if hash and empty_tree then
190193 local stat = exec_git { " diff" , " --shortstat" , empty_tree , hash }
191194 local ins = (stat [1 ] or " " ):match " (%d+) insertion"
192- table.insert (values , tonumber (ins ) or 0 )
195+ table.insert (values , ins and tonumber (ins , 10 ) or 0 )
193196 table.insert (labels , date )
194197 end
195198 end
0 commit comments