@@ -923,20 +923,54 @@ local function java_stack_trace_to_snacks_items(stack_trace)
923923 return nil
924924end
925925
926+ --- @param cols table
927+ --- @param element JavaHelpers.StackTraceElement
928+ --- @param max_class_and_method_length integer
929+ local function add_snacks_picker_columns_for_element (cols , element , max_class_and_method_length )
930+ assert (element )
931+ assert (max_class_and_method_length > 0 )
932+
933+ local class_name = element .class_name
934+ local method_name = element .method_name
935+ local width = # class_name + 1 + # method_name
936+
937+ assert (width <= max_class_and_method_length )
938+
939+ table.insert (cols , { class_name , " SnacksLabel" })
940+ table.insert (cols , { " ." , " SnacksPickerSpecial" })
941+ table.insert (cols , { method_name , " SnacksPickerSpecial" })
942+ table.insert (cols , { string.rep (" " , max_class_and_method_length - width + 2 ), " SnacksLabel" })
943+
944+ local file_name = element .file_name
945+
946+ if file_name then
947+ table.insert (cols , { file_name , " SnacksPickerFile" })
948+ table.insert (cols , { " :" , " SnacksLabel" })
949+ end
950+
951+ table.insert (cols , { tostring (element .line_number ), " SnacksPickerRow" })
952+ end
953+
926954--- @param stack_trace JavaHelpers.StackTraceElement[]
927955--- @param initially_selected integer
928- local function pick_java_stack_trace_line (stack_trace , initially_selected )
956+ --- @return integer ? selected_index
957+ local function await_pick_java_stack_trace_line (stack_trace , initially_selected )
958+ local co = coroutine.running ()
959+
960+ assert (co , " await_pick_java_stack_trace_line must be called within a coroutine" )
961+
929962 if # stack_trace == 1 then
930- go_to_java_stack_trace_element (stack_trace [1 ])
931- return
963+ return 1
932964 end
933965
934966 local items = java_stack_trace_to_snacks_items (stack_trace )
935967
936968 if not items then
937- return
969+ return nil
938970 end
939971
972+ assert (# items > 0 )
973+
940974 local max_class_and_method_length = 1
941975
942976 for _ , item in ipairs (items ) do
@@ -960,43 +994,23 @@ local function pick_java_stack_trace_line(stack_trace, initially_selected)
960994 local cols = {}
961995 local element = item .java_stack_trace_element
962996
963- assert (element )
964-
965- local class_name = element .class_name
966- local method_name = element .method_name
967- local width = # class_name + 1 + # method_name
968-
969- table.insert (cols , { class_name , " SnacksLabel" })
970- table.insert (cols , { " ." , " SnacksPickerSpecial" })
971- table.insert (cols , { method_name , " SnacksPickerSpecial" })
972- table.insert (cols , { string.rep (" " , max_class_and_method_length - width + 2 ), " SnacksLabel" })
973-
974- local file_name = element .file_name
975-
976- if file_name then
977- table.insert (cols , { file_name , " SnacksPickerFile" })
978- table.insert (cols , { " :" , " SnacksLabel" })
979- end
980-
981- table.insert (cols , { tostring (element .line_number ), " SnacksPickerRow" })
997+ add_snacks_picker_columns_for_element (cols , element , max_class_and_method_length )
982998
983999 return cols
9841000 end ,
9851001 confirm = function (p , item )
9861002 p :close ()
987- if item then
988- utils .go_to_file_and_line_number (item .file , item .pos [1 ])
989-
990- if stack_trace == current_loaded_stack_trace then
991- local index = item .java_stack_trace_index
992-
993- if index then
994- current_loaded_stack_trace_index = index
995- end
1003+ vim .schedule (function ()
1004+ if item then
1005+ coroutine.resume (co , item .java_stack_trace_index )
1006+ else
1007+ coroutine.resume (co , nil )
9961008 end
997- end
1009+ end )
9981010 end ,
9991011 })
1012+
1013+ return coroutine.yield ()
10001014end
10011015
10021016--- @param register_name_or_text_to_parse string ? If a single character then defines the register name , if multiple characters then will parse trhe supplied text , if nil or empty then uses the text around the current cursor position
@@ -1009,7 +1023,18 @@ function M.pick_java_stack_trace_line(register_name_or_text_to_parse)
10091023 return
10101024 end
10111025
1012- pick_java_stack_trace_line (current_loaded_stack_trace , current_loaded_stack_trace_index )
1026+ local stack_trace = current_loaded_stack_trace
1027+
1028+ local index = await_pick_java_stack_trace_line (stack_trace , current_loaded_stack_trace_index )
1029+
1030+ if index then
1031+ local element = stack_trace [index ]
1032+
1033+ go_to_java_stack_trace_element (element )
1034+
1035+ current_loaded_stack_trace = stack_trace
1036+ current_loaded_stack_trace_index = index
1037+ end
10131038 end )
10141039end
10151040
@@ -1042,7 +1067,7 @@ local function select_obfuscation_file_if_needed()
10421067 end
10431068end
10441069
1045- --- @param register_name string ? Register name or nil to deobfuscate under the cursor
1070+ --- @param register_name string Register name or nil to deobfuscate under the cursor
10461071local function deobfuscate_register (register_name )
10471072 select_obfuscation_file_if_needed ()
10481073
@@ -1182,7 +1207,6 @@ end
11821207--- @param cursor_line integer
11831208--- @return integer ? next_start_line
11841209local function find_prev_stack_trace (lines , cursor_line )
1185- local line_count = lines .line_count
11861210 local line_to_start_from = cursor_line
11871211
11881212 -- Go past the beginning of the current stack trace
@@ -1273,12 +1297,18 @@ function M.go_to_prev_stack_trace(win)
12731297 vim .api .nvim_win_set_cursor (win , { line_to_go_to , 0 })
12741298end
12751299
1300+ --- @class JavaHelpers.FoundStackTrace
1301+ --- @field start_line integer
1302+ --- @field element JavaHelpers.StackTraceElement
1303+
12761304--- @param lines JavaHelpers.TextLines
1277- --- @return integer [] start_lines
1278- local function find_all_stack_trace_start_lines (lines )
1305+ --- @return JavaHelpers.FoundStackTrace [] found_stack_traces
1306+ local function find_all_stack_traces (lines )
12791307 local line = 1
12801308 local count = lines .line_count
1281- local start_lines = {}
1309+ ---
1310+ --- @type JavaHelpers.FoundStackTrace[]
1311+ local found_stack_traces = {}
12821312
12831313 while line <= count do
12841314 local start_line = find_next_stack_trace (lines , line )
@@ -1293,33 +1323,141 @@ local function find_all_stack_trace_start_lines(lines)
12931323 assert (first_line )
12941324 assert (last_line )
12951325
1296- table.insert (start_lines , first_line )
1326+ table.insert (found_stack_traces , {
1327+ start_line = first_line ,
1328+ element = element ,
1329+ })
1330+
12971331 line = last_line
12981332 end
12991333
1300- return start_lines
1334+ return found_stack_traces
1335+ end
1336+
1337+ --- @param bufnr integer
1338+ --- @param found_stack_traces JavaHelpers.FoundStackTrace[]
1339+ --- @return JavaHelpers.FoundStackTrace ? selected
1340+ local function await_pick_java_stack_trace (bufnr , found_stack_traces )
1341+ log .trace (" Selecting line number in buffer " .. bufnr )
1342+
1343+ local co = coroutine.running ()
1344+
1345+ assert (co , " await_pick_line_number_in_file must be called within a coroutine" )
1346+
1347+ if # found_stack_traces == 0 then
1348+ return nil
1349+ end
1350+
1351+ if # found_stack_traces == 1 then
1352+ return found_stack_traces [1 ]
1353+ end
1354+
1355+ local is_file = vim .api .nvim_get_option_value (" buftype" , { buf = bufnr }) == " "
1356+ local file = nil
1357+
1358+ if is_file then
1359+ file = vim .api .nvim_buf_get_name (bufnr )
1360+ else
1361+ -- This is not a normal file so write it to a temporary file
1362+ file = vim .fn .tempname ()
1363+
1364+ local f = io.open (file , " w" )
1365+
1366+ if f then
1367+ f :write (utils .get_buffer_text (bufnr ))
1368+ f :close ()
1369+ end
1370+ end
1371+
1372+ local picker = require (" snacks.picker" )
1373+ local items = {}
1374+ local max_class_and_method_length = 1
1375+
1376+ for _ , found_stack_trace in ipairs (found_stack_traces ) do
1377+ local line_number = found_stack_trace .start_line
1378+ local element = found_stack_trace .element
1379+
1380+ local class_name = element .class_name
1381+ local method_name = element .method_name
1382+ local width = # class_name + 1 + # method_name
1383+
1384+ if width > max_class_and_method_length then
1385+ max_class_and_method_length = width
1386+ end
1387+
1388+ table.insert (items , {
1389+ file = file ,
1390+ pos = { found_stack_trace .start_line , 0 },
1391+ found_java_stack_trace = found_stack_trace ,
1392+ })
1393+ end
1394+
1395+ picker .pick ({
1396+ items = items ,
1397+ prompt = " Select strack trace: " ,
1398+ format = function (item , _ )
1399+ local found_java_stack_trace = item .found_java_stack_trace
1400+ local element = found_java_stack_trace .element
1401+ local cols = {}
1402+
1403+ add_snacks_picker_columns_for_element (cols , element , max_class_and_method_length )
1404+
1405+ return cols
1406+ end ,
1407+ confirm = function (p , item )
1408+ p :close ()
1409+
1410+ if not is_file then
1411+ os.remove (file )
1412+ end
1413+
1414+ vim .schedule (function ()
1415+ if not item then
1416+ log .trace (" No stack trace selected" )
1417+ coroutine.resume (co , nil )
1418+ return
1419+ end
1420+
1421+ local selected = item .found_java_stack_trace
1422+
1423+ log .trace (" Selected stack trace " .. selected .start_line .. " in " .. bufnr )
1424+
1425+ coroutine.resume (co , selected )
1426+ end )
1427+ end ,
1428+ })
1429+
1430+ return coroutine.yield ()
13011431end
13021432
13031433function M .pick_java_stack_trace (win )
1434+ if win == 0 then
1435+ win = vim .api .nvim_get_current_win ()
1436+ end
1437+
13041438 local bufnr = vim .api .nvim_win_get_buf (win )
13051439 local file_path = vim .api .nvim_buf_get_name (bufnr )
13061440 local lines = utils .create_text_lines_from_buffer (bufnr )
1307- local start_lines = find_all_stack_trace_start_lines (lines )
1441+ local found_stack_traces = find_all_stack_traces (lines )
13081442
1309- if # start_lines == 0 then
1443+ if # found_stack_traces == 0 then
13101444 log .info (" No stack traces found" )
13111445 return
13121446 end
13131447
1448+ if # found_stack_traces == 1 then
1449+ vim .api .nvim_win_set_buf (win , bufnr )
1450+ vim .api .nvim_win_set_cursor (win , { found_stack_traces [1 ].start_line , 0 })
1451+ return
1452+ end
1453+
13141454 run_in_bg (function ()
1315- if # start_lines == 1 then
1316- vim .api .nvim_win_set_cursor (win , { start_lines [1 ], 0 })
1317- else
1318- local selected_line = utils .await_pick_line_number_in_file (" Select strack trace: " , file_path , start_lines )
1455+ local selected_stack_trace = await_pick_java_stack_trace (bufnr , found_stack_traces )
13191456
1320- if selected_line then
1321- vim .api .nvim_win_set_cursor (win , { selected_line , 0 })
1322- end
1457+ if selected_stack_trace then
1458+ vim .api .nvim_set_current_win (win )
1459+ vim .api .nvim_win_set_buf (win , bufnr )
1460+ vim .api .nvim_win_set_cursor (win , { selected_stack_trace .start_line , 0 })
13231461 end
13241462 end )
13251463end
@@ -1346,7 +1484,7 @@ function M.setup(opts)
13461484 nargs = " ?" ,
13471485 })
13481486
1349- vim .api .nvim_create_user_command (" JavaHelpersPickStackTrace" , function (command_opts )
1487+ vim .api .nvim_create_user_command (" JavaHelpersPickStackTrace" , function ()
13501488 M .pick_java_stack_trace (0 )
13511489 end , {
13521490 desc = " Pick Java stack trace" ,
0 commit comments