11use std:: fs;
2- use zed:: { CodeLabel , CodeLabelSpan , LanguageServerId , Result , lsp:: CompletionKind } ;
3- use zed_extension_api:: { self as zed} ;
2+ use zed:: lsp:: CompletionKind ;
3+ use zed:: { CodeLabel , CodeLabelSpan , LanguageServerId } ;
4+ use zed_extension_api:: { self as zed, Result , serde_json:: Value } ;
45
56struct EmmyLuaExtension {
67 cached_binary_path : Option < String > ,
8+ cached_dap_binary_path : Option < String > ,
79}
810
911impl EmmyLuaExtension {
@@ -20,6 +22,7 @@ impl EmmyLuaExtension {
2022 }
2123 }
2224
25+ // First check if emmylua is in PATH
2326 if let Some ( path) = worktree. which ( "emmylua_ls" ) {
2427 return Ok ( path) ;
2528 }
@@ -124,6 +127,7 @@ impl zed::Extension for EmmyLuaExtension {
124127 fn new ( ) -> Self {
125128 Self {
126129 cached_binary_path : None ,
130+ cached_dap_binary_path : None ,
127131 }
128132 }
129133
@@ -267,6 +271,154 @@ impl zed::Extension for EmmyLuaExtension {
267271
268272 Ok ( Some ( settings) )
269273 }
274+
275+ // DAP Support for EmmyLua debugger
276+ fn get_dap_binary (
277+ & mut self ,
278+ adapter_name : String ,
279+ _config : zed:: DebugTaskDefinition ,
280+ user_provided_debug_adapter_path : Option < String > ,
281+ worktree : & zed:: Worktree ,
282+ ) -> std:: result:: Result < zed:: DebugAdapterBinary , String > {
283+ if adapter_name != "emmylua_new" {
284+ return Err ( format ! ( "Unknown debug adapter: {}" , adapter_name) ) ;
285+ }
286+
287+ let default_request_args = zed:: StartDebuggingRequestArguments {
288+ configuration : Default :: default ( ) ,
289+ request : zed:: StartDebuggingRequestArgumentsRequest :: Launch ,
290+ } ;
291+
292+ // Check if user provided a custom path
293+ if let Some ( path) = user_provided_debug_adapter_path {
294+ self . cached_dap_binary_path = Some ( path. clone ( ) ) ;
295+ return Ok ( zed:: DebugAdapterBinary {
296+ command : Some ( path) ,
297+ arguments : vec ! [ ] ,
298+ envs : vec ! [ ] ,
299+ cwd : None ,
300+ connection : None ,
301+ request_args : default_request_args,
302+ } ) ;
303+ }
304+
305+ // Try to find emmylua_dap in PATH
306+ if let Some ( path) = worktree. which ( "emmylua_dap" ) {
307+ return Ok ( zed:: DebugAdapterBinary {
308+ command : Some ( path) ,
309+ arguments : vec ! [ ] ,
310+ envs : vec ! [ ] ,
311+ cwd : None ,
312+ connection : None ,
313+ request_args : default_request_args,
314+ } ) ;
315+ }
316+
317+ // Check cached path
318+ if let Some ( path) = & self . cached_dap_binary_path {
319+ if fs:: metadata ( path) . map_or ( false , |stat| stat. is_file ( ) ) {
320+ return Ok ( zed:: DebugAdapterBinary {
321+ command : Some ( path. clone ( ) ) ,
322+ arguments : vec ! [ ] ,
323+ envs : vec ! [ ] ,
324+ cwd : None ,
325+ connection : None ,
326+ request_args : default_request_args,
327+ } ) ;
328+ }
329+ }
330+
331+ // Try to download from GitHub releases
332+ let release = zed:: latest_github_release (
333+ "EmmyLuaLs/emmylua_dap" ,
334+ zed:: GithubReleaseOptions {
335+ require_assets : true ,
336+ pre_release : false ,
337+ } ,
338+ )
339+ . map_err ( |e| format ! ( "Failed to get latest release: {}" , e) ) ?;
340+
341+ let ( platform, arch) = zed:: current_platform ( ) ;
342+ let asset_name = format ! (
343+ "emmylua_dap-{os}-{arch}{glibc}.{extension}" ,
344+ os = match platform {
345+ zed:: Os :: Mac => "darwin" ,
346+ zed:: Os :: Linux => "linux" ,
347+ zed:: Os :: Windows => "win32" ,
348+ } ,
349+ arch = match arch {
350+ zed:: Architecture :: Aarch64 => match platform {
351+ zed:: Os :: Linux => "aarch64" ,
352+ zed:: Os :: Windows | zed:: Os :: Mac => "arm64" ,
353+ } ,
354+ zed:: Architecture :: X8664 => "x64" ,
355+ zed:: Architecture :: X86 => return Err ( "unsupported platform x86" . into( ) ) ,
356+ } ,
357+ glibc = match platform {
358+ zed:: Os :: Linux => "-glibc.2.17" ,
359+ zed:: Os :: Windows | zed:: Os :: Mac => "" ,
360+ } ,
361+ extension = match platform {
362+ zed:: Os :: Mac | zed:: Os :: Linux => "tar.gz" ,
363+ zed:: Os :: Windows => "zip" ,
364+ } ,
365+ ) ;
366+
367+ let asset = release
368+ . assets
369+ . iter ( )
370+ . find ( |asset| asset. name . contains ( & asset_name) )
371+ . ok_or_else ( || format ! ( "No asset found matching pattern: {}" , asset_name) ) ?;
372+
373+ let version_dir = format ! ( "emmylua_dap-{}" , release. version) ;
374+ let binary_name = format ! (
375+ "emmylua_dap{}" ,
376+ match platform {
377+ zed:: Os :: Mac | zed:: Os :: Linux => "" ,
378+ zed:: Os :: Windows => ".exe" ,
379+ }
380+ ) ;
381+ let binary_path = format ! ( "{}/{}" , version_dir, binary_name) ;
382+
383+ if !fs:: metadata ( & binary_path) . map_or ( false , |stat| stat. is_file ( ) ) {
384+ zed:: download_file (
385+ & asset. download_url ,
386+ & version_dir,
387+ match platform {
388+ zed:: Os :: Mac | zed:: Os :: Linux => zed:: DownloadedFileType :: GzipTar ,
389+ zed:: Os :: Windows => zed:: DownloadedFileType :: Zip ,
390+ } ,
391+ )
392+ . map_err ( |e| format ! ( "Failed to download DAP binary: {}" , e) ) ?;
393+ }
394+
395+ self . cached_dap_binary_path = Some ( binary_path. clone ( ) ) ;
396+ Ok ( zed:: DebugAdapterBinary {
397+ command : Some ( binary_path) ,
398+ arguments : vec ! [ "--log-level" . to_string( ) , "debug" . to_string( ) ] ,
399+ envs : vec ! [ ] ,
400+ cwd : None ,
401+ connection : None ,
402+ request_args : default_request_args,
403+ } )
404+ }
405+
406+ fn dap_request_kind (
407+ & mut self ,
408+ _adapter_name : String ,
409+ config : Value ,
410+ ) -> std:: result:: Result < zed:: StartDebuggingRequestArgumentsRequest , String > {
411+ let request_type = config
412+ . get ( "request" )
413+ . and_then ( |v| v. as_str ( ) )
414+ . unwrap_or ( "launch" ) ;
415+
416+ match request_type {
417+ "launch" => Ok ( zed:: StartDebuggingRequestArgumentsRequest :: Launch ) ,
418+ "attach" => Ok ( zed:: StartDebuggingRequestArgumentsRequest :: Attach ) ,
419+ _ => Err ( format ! ( "Unknown request type: {}" , request_type) ) ,
420+ }
421+ }
270422}
271423
272424zed:: register_extension!( EmmyLuaExtension ) ;
0 commit comments