@@ -9,22 +9,62 @@ local InputWidget = require("chatgpt.common.input_widget")
99
1010local namespace_id = vim .api .nvim_create_namespace (" ChatGPTNS" )
1111
12+ -- Get date group for a timestamp
13+ local function get_date_group (ts )
14+ local now = os.time ()
15+ local today_start = os.time ({
16+ year = os.date (" %Y" ),
17+ month = os.date (" %m" ),
18+ day = os.date (" %d" ),
19+ hour = 0 ,
20+ min = 0 ,
21+ sec = 0 ,
22+ })
23+ local yesterday_start = today_start - 86400
24+ local week_start = today_start - (86400 * 7 )
25+ local month_start = today_start - (86400 * 30 )
26+
27+ if ts >= today_start then
28+ return " Today"
29+ elseif ts >= yesterday_start then
30+ return " Yesterday"
31+ elseif ts >= week_start then
32+ return " This Week"
33+ elseif ts >= month_start then
34+ return " This Month"
35+ else
36+ return " Older"
37+ end
38+ end
39+
1240M .set_current_line = function ()
1341 M .current_line , _ = unpack (vim .api .nvim_win_get_cursor (M .panel .winid ))
1442 M .render_list ()
1543end
1644
45+ -- Get the session index for the current cursor line
46+ M .get_current_session_index = function ()
47+ return M .line_to_session and M .line_to_session [M .current_line ] or nil
48+ end
49+
1750M .set_session = function ()
18- M .active_line = M .current_line
19- local selected = M .sessions [M .current_line ]
51+ local session_idx = M .get_current_session_index ()
52+ if not session_idx then
53+ return -- On a header line
54+ end
55+ M .active_line = session_idx
56+ local selected = M .sessions [session_idx ]
2057 local session = Session .new ({ filename = selected .filename })
2158 M .render_list ()
2259 M .set_session_cb (session )
2360end
2461
2562M .rename_session = function ()
26- M .active_line = M .current_line
27- local selected = M .sessions [M .current_line ]
63+ local session_idx = M .get_current_session_index ()
64+ if not session_idx then
65+ return -- On a header line
66+ end
67+ local selected = M .sessions [session_idx ]
2868 local session = Session .new ({ filename = selected .filename })
2969 local input_widget = InputWidget (" New Name:" , function (value )
3070 if value ~= nil and value ~= " " then
@@ -37,12 +77,16 @@ M.rename_session = function()
3777end
3878
3979M .delete_session = function ()
40- local selected = M .sessions [M .current_line ]
41- if M .active_line ~= M .current_line then
80+ local session_idx = M .get_current_session_index ()
81+ if not session_idx then
82+ return -- On a header line
83+ end
84+ if M .active_line ~= session_idx then
85+ local selected = M .sessions [session_idx ]
4286 local session = Session .new ({ filename = selected .filename })
4387 session :delete ()
4488 M .sessions = Session .list_sessions ()
45- if M .active_line > M . current_line then
89+ if M .active_line > session_idx then
4690 M .active_line = M .active_line - 1
4791 end
4892 M .render_list ()
5498M .render_list = function ()
5599 vim .api .nvim_buf_clear_namespace (M .panel .bufnr , namespace_id , 0 , - 1 )
56100
57- local details = {}
58- for i , session in pairs ( M . sessions ) do
59- local icon = i == M . active_line and Config . options . chat . sessions_window . active_sign
60- or Config . options . chat . sessions_window . inactive_sign
61- local cls = i == M . active_line and Config . options . highlights . active_session or " Comment "
62- local name = Utils . trimText ( session . name , 30 )
63- local vt = {
64- { (M .current_line == i and Config . options . chat . sessions_window . current_line_sign or " " ) .. icon .. name , cls },
65- }
66- table.insert (details , vt )
101+ -- Group sessions by date
102+ local groups = {}
103+ local group_order = { " Today " , " Yesterday " , " This Week " , " This Month " , " Older " }
104+ for _ , g in ipairs ( group_order ) do
105+ groups [ g ] = {}
106+ end
107+
108+ for i , session in ipairs (M .sessions ) do
109+ local group = get_date_group ( session . ts )
110+ table.insert (groups [ group ], { index = i , session = session } )
67111 end
68112
69- local line = 1
113+ -- Build display list with headers
114+ local display_lines = {}
115+ local line_to_session = {} -- Maps display line to session index
116+
117+ for _ , group_name in ipairs (group_order ) do
118+ local group_sessions = groups [group_name ]
119+ if # group_sessions > 0 then
120+ -- Add header
121+ table.insert (display_lines , { type = " header" , text = group_name })
122+ -- Add sessions
123+ for _ , entry in ipairs (group_sessions ) do
124+ table.insert (display_lines , { type = " session" , index = entry .index , session = entry .session })
125+ line_to_session [# display_lines ] = entry .index
126+ end
127+ end
128+ end
129+
130+ M .line_to_session = line_to_session
131+
132+ -- Create buffer lines
70133 local empty_lines = {}
71- for _ = 1 , # details do
134+ for _ = 1 , # display_lines do
72135 table.insert (empty_lines , " " )
73136 end
74-
75- vim .api .nvim_buf_set_lines (M .panel .bufnr , line - 1 , line - 1 + # empty_lines , false , empty_lines )
76- for _ , d in ipairs (details ) do
77- M .vts [line - 1 ] = vim .api .nvim_buf_set_extmark (
78- M .panel .bufnr ,
79- namespace_id ,
80- line - 1 ,
81- 0 ,
82- { virt_text = d , virt_text_pos = " overlay" }
83- )
84- line = line + 1
137+ vim .api .nvim_buf_set_lines (M .panel .bufnr , 0 , - 1 , false , empty_lines )
138+
139+ -- Render each line
140+ for line_num , item in ipairs (display_lines ) do
141+ local line_idx = line_num - 1
142+
143+ if item .type == " header" then
144+ -- Render header with separator line
145+ local header_text = " ── " .. item .text .. " " .. string.rep (" ─" , 20 )
146+ vim .api .nvim_buf_set_extmark (M .panel .bufnr , namespace_id , line_idx , 0 , {
147+ virt_text = { { header_text , " ChatGPTSessionHeader" } },
148+ virt_text_pos = " overlay" ,
149+ })
150+ else
151+ -- Render session
152+ local i = item .index
153+ local session = item .session
154+ local is_active = (i == M .active_line )
155+ local is_current = (M .line_to_session [line_num ] == M .line_to_session [M .current_line ])
156+
157+ local cursor = is_current and Config .options .chat .sessions_window .current_line_sign or " "
158+ local icon = is_active and Config .options .chat .sessions_window .active_sign or Config .options .chat .sessions_window .inactive_sign
159+ local cls = is_active and Config .options .highlights .active_session or " Comment"
160+ local name = Utils .trimText (session .name , 28 )
161+
162+ vim .api .nvim_buf_set_extmark (M .panel .bufnr , namespace_id , line_idx , 0 , {
163+ virt_text = { { cursor , " ChatGPTSessionCursor" }, { icon .. name , cls } },
164+ virt_text_pos = " overlay" ,
165+ })
166+ end
85167 end
86168end
87169
0 commit comments