@@ -750,11 +750,12 @@ defmodule ElixirLS.Debugger.Server do
750
750
:normal ->
751
751
:ok
752
752
753
- :shutdown ->
754
- :ok
753
+ { % ServerError { } = error , stack } ->
754
+ exit_code = 1
755
+ Output . send_event ( "exited" , % { "exitCode" => exit_code } )
756
+ Output . send_event ( "terminated" , % { "restart" => false } )
755
757
756
- { :shutdown , _ } ->
757
- :ok
758
+ reraise error , stack
758
759
759
760
_other ->
760
761
message = "Launch request failed with reason\n " <> Exception . format_exit ( reason )
@@ -769,6 +770,7 @@ defmodule ElixirLS.Debugger.Server do
769
770
message: "launchError" ,
770
771
format: message ,
771
772
variables: % { } ,
773
+ send_telemetry: false ,
772
774
show_user: true
773
775
end
774
776
end
@@ -1630,6 +1632,16 @@ defmodule ElixirLS.Debugger.Server do
1630
1632
1631
1633
project_dir =
1632
1634
if project_dir not in [ nil , "" ] do
1635
+ if not is_binary ( project_dir ) do
1636
+ raise ServerError ,
1637
+ message: "argumentError" ,
1638
+ format:
1639
+ "invalid `projectDir` in launch config. Expected string or nil, got #{ inspect ( project_dir ) } " ,
1640
+ variables: % { } ,
1641
+ send_telemetry: false ,
1642
+ show_user: true
1643
+ end
1644
+
1633
1645
Output . debugger_console ( "Starting debugger in directory: #{ project_dir } \n " )
1634
1646
project_dir
1635
1647
else
@@ -1643,12 +1655,44 @@ defmodule ElixirLS.Debugger.Server do
1643
1655
end
1644
1656
1645
1657
task = config [ "task" ]
1658
+
1659
+ if not ( is_nil ( task ) or is_binary ( task ) ) do
1660
+ raise ServerError ,
1661
+ message: "argumentError" ,
1662
+ format:
1663
+ "invalid `taskArgs` in launch config. Expected string or nil, got #{ inspect ( task ) } " ,
1664
+ variables: % { } ,
1665
+ send_telemetry: false ,
1666
+ show_user: true
1667
+ end
1668
+
1646
1669
task_args = config [ "taskArgs" ] || [ ]
1670
+
1671
+ if not ( is_list ( task_args ) and Enum . all? ( task_args , & is_binary / 1 ) ) do
1672
+ raise ServerError ,
1673
+ message: "argumentError" ,
1674
+ format:
1675
+ "invalid `taskArgs` in launch config. Expected list of strings or nil, got #{ inspect ( task_args ) } " ,
1676
+ variables: % { } ,
1677
+ send_telemetry: false ,
1678
+ show_user: true
1679
+ end
1680
+
1647
1681
auto_interpret_files? = Map . get ( config , "debugAutoInterpretAllModules" , true )
1648
1682
1649
1683
set_env_vars ( config [ "env" ] )
1650
1684
1651
- File . cd! ( project_dir )
1685
+ try do
1686
+ File . cd! ( project_dir )
1687
+ rescue
1688
+ e in File.Error ->
1689
+ raise ServerError ,
1690
+ message: "argumentError" ,
1691
+ format: Exception . format_banner ( :error , e , __STACKTRACE__ ) ,
1692
+ variables: % { } ,
1693
+ send_telemetry: false ,
1694
+ show_user: true
1695
+ end
1652
1696
1653
1697
# the startup sequence here is taken from
1654
1698
# https://github.com/elixir-lang/elixir/blob/v1.14.4/lib/mix/lib/mix/cli.ex#L158
@@ -1683,10 +1727,22 @@ defmodule ElixirLS.Debugger.Server do
1683
1727
# make sure ANSI is disabled
1684
1728
Application . put_env ( :elixir , :ansi_enabled , false )
1685
1729
1686
- unless is_list ( task_args ) and "--no-compile" in task_args do
1687
- case Mix.Task . run ( "compile" , [ "--ignore-module-conflict" ] ) do
1688
- { :error , reason } ->
1689
- raise reason
1730
+ unless "--no-compile" in task_args do
1731
+ case Mix.Task . run ( "compile" , [ "--ignore-module-conflict" , "--return-errors" ] ) do
1732
+ { :error , diagnostics } ->
1733
+ message =
1734
+ diagnostics
1735
+ |> Enum . filter ( fn % Mix.Task.Compiler.Diagnostic { } = diag ->
1736
+ diag . severity == :error
1737
+ end )
1738
+ |> Enum . map_join ( "\n " , fn % Mix.Task.Compiler.Diagnostic { } = diag -> diag . message end )
1739
+
1740
+ raise ServerError ,
1741
+ message: "launchError" ,
1742
+ format: message ,
1743
+ variables: % { } ,
1744
+ send_telemetry: false ,
1745
+ show_user: true
1690
1746
1691
1747
_ ->
1692
1748
:ok
@@ -1703,6 +1759,16 @@ defmodule ElixirLS.Debugger.Server do
1703
1759
config
1704
1760
|> Map . get ( "excludeModules" , [ ] )
1705
1761
1762
+ if not ( is_list ( exclude_module_names ) and Enum . all? ( exclude_module_names , & is_binary / 1 ) ) do
1763
+ raise ServerError ,
1764
+ message: "argumentError" ,
1765
+ format:
1766
+ "invalid `excludeModules` in launch config. Expected list of strings or nil, got #{ inspect ( exclude_module_names ) } " ,
1767
+ variables: % { } ,
1768
+ send_telemetry: false ,
1769
+ show_user: true
1770
+ end
1771
+
1706
1772
exclude_module_pattern =
1707
1773
exclude_module_names
1708
1774
|> Enum . map ( & wildcard_module_name_to_pattern / 1 )
@@ -1714,17 +1780,57 @@ defmodule ElixirLS.Debugger.Server do
1714
1780
auto_interpret_modules ( Mix.Project . build_path ( ) , exclude_module_pattern )
1715
1781
end
1716
1782
1717
- if required_files = config [ "requireFiles" ] , do: require_files ( required_files )
1783
+ required_files = Map . get ( config , "requireFiles" , [ ] )
1718
1784
1719
- if interpret_modules_patterns = config [ "debugInterpretModulesPatterns" ] do
1720
- interpret_specified_modules ( interpret_modules_patterns , exclude_module_pattern )
1785
+ if not ( is_list ( required_files ) and Enum . all? ( required_files , & is_binary / 1 ) ) do
1786
+ raise ServerError ,
1787
+ message: "argumentError" ,
1788
+ format:
1789
+ "invalid `requireFiles` in launch config. Expected list of strings or nil, got #{ inspect ( required_files ) } " ,
1790
+ variables: % { } ,
1791
+ send_telemetry: false ,
1792
+ show_user: true
1721
1793
end
1794
+
1795
+ require_files ( required_files )
1796
+
1797
+ interpret_modules_patterns = Map . get ( config , "debugInterpretModulesPatterns" , [ ] )
1798
+
1799
+ if not ( is_list ( interpret_modules_patterns ) and
1800
+ Enum . all? ( interpret_modules_patterns , & is_binary / 1 ) ) do
1801
+ raise ServerError ,
1802
+ message: "argumentError" ,
1803
+ format:
1804
+ "invalid `debugInterpretModulesPatterns` in launch config. Expected list of strings or nil, got #{ inspect ( interpret_modules_patterns ) } " ,
1805
+ variables: % { } ,
1806
+ send_telemetry: false ,
1807
+ show_user: true
1808
+ end
1809
+
1810
+ interpret_specified_modules ( interpret_modules_patterns , exclude_module_pattern )
1722
1811
else
1723
1812
Output . debugger_console ( "Running without debugging" )
1724
1813
end
1725
1814
1726
1815
updated_config = Map . merge ( config , % { "task" => task , "taskArgs" => task_args } )
1727
1816
send ( server , { :ok , updated_config } )
1817
+ rescue
1818
+ e in [
1819
+ Mix.Error ,
1820
+ Mix.NoProjectError ,
1821
+ Mix.ElixirVersionError ,
1822
+ Mix.InvalidTaskError ,
1823
+ Mix.NoTaskError ,
1824
+ CompileError ,
1825
+ SyntaxError ,
1826
+ TokenMissingError
1827
+ ] ->
1828
+ raise ServerError ,
1829
+ message: "launchError" ,
1830
+ format: Exception . format_banner ( :error , e , __STACKTRACE__ ) ,
1831
+ variables: % { } ,
1832
+ send_telemetry: false ,
1833
+ show_user: true
1728
1834
end
1729
1835
1730
1836
defp set_env_vars ( env ) when is_map ( env ) do
@@ -1736,27 +1842,43 @@ defmodule ElixirLS.Debugger.Server do
1736
1842
"Cannot set environment variables to #{ inspect ( env ) } : #{ Exception . message ( e ) } "
1737
1843
)
1738
1844
1739
- Output . debugger_important (
1740
- "Invalid `env` in launch configuration. Expected a map with string key value pairs, got #{ inspect ( env ) } ."
1741
- )
1845
+ raise ServerError ,
1846
+ message: "argumentError" ,
1847
+ format:
1848
+ "invalid `env` in launch configuration. Expected a map with string key value pairs, got #{ inspect ( env ) } " ,
1849
+ variables: % { } ,
1850
+ send_telemetry: false ,
1851
+ show_user: true
1742
1852
end
1743
1853
1744
1854
:ok
1745
1855
end
1746
1856
1747
1857
defp set_env_vars ( env ) when is_nil ( env ) , do: :ok
1748
1858
1859
+ defp set_env_vars ( env ) do
1860
+ raise ServerError ,
1861
+ message: "argumentError" ,
1862
+ format:
1863
+ "invalid `env` in launch configuration. Expected a map with string key value pairs, got #{ inspect ( env ) } " ,
1864
+ variables: % { } ,
1865
+ send_telemetry: false ,
1866
+ show_user: true
1867
+ end
1868
+
1749
1869
defp set_stack_trace_mode ( "all" ) , do: :int . stack_trace ( :all )
1750
1870
defp set_stack_trace_mode ( "no_tail" ) , do: :int . stack_trace ( :no_tail )
1751
1871
defp set_stack_trace_mode ( "false" ) , do: :int . stack_trace ( false )
1752
1872
defp set_stack_trace_mode ( false ) , do: :int . stack_trace ( false )
1753
1873
defp set_stack_trace_mode ( nil ) , do: nil
1754
1874
1755
- defp set_stack_trace_mode ( _ ) do
1875
+ defp set_stack_trace_mode ( mode ) do
1756
1876
raise ServerError ,
1757
1877
message: "argumentError" ,
1758
- format: "stackTraceMode must be `all`, `no_tail`, or `false`" ,
1878
+ format:
1879
+ "invalid `stackTraceMode` in launch configuration. Must be `all`, `no_tail` or `false`, got #{ inspect ( mode ) } " ,
1759
1880
variables: % { } ,
1881
+ send_telemetry: false ,
1760
1882
show_user: true
1761
1883
end
1762
1884
@@ -1861,9 +1983,11 @@ defmodule ElixirLS.Debugger.Server do
1861
1983
# files to load via the launch configuration. They must be in the correct order (for example,
1862
1984
# test helpers before tests). We save the .beam files to a temporary folder which we add to the
1863
1985
# code path.
1986
+ defp require_files ( [ ] ) , do: :ok
1987
+
1864
1988
defp require_files ( required_files ) do
1865
- { :ok , _ } = File . rm_rf ( @ temp_beam_dir )
1866
- :ok = File . mkdir_p ( @ temp_beam_dir )
1989
+ File . rm_rf! ( @ temp_beam_dir )
1990
+ File . mkdir_p! ( @ temp_beam_dir )
1867
1991
true = Code . append_path ( Path . expand ( @ temp_beam_dir ) )
1868
1992
1869
1993
for path <- required_files ,
@@ -1874,6 +1998,8 @@ defmodule ElixirLS.Debugger.Server do
1874
1998
do: save_and_reload ( module , beam_bin )
1875
1999
end
1876
2000
2001
+ defp interpret_specified_modules ( [ ] , _exclude_module_pattern ) , do: :ok
2002
+
1877
2003
defp interpret_specified_modules ( file_patterns , exclude_module_pattern ) do
1878
2004
regexes =
1879
2005
Enum . map ( file_patterns , fn pattern ->
@@ -1886,6 +2012,7 @@ defmodule ElixirLS.Debugger.Server do
1886
2012
message: "argumentError" ,
1887
2013
format: "Unable to compile file pattern {pattern} into a regex: {error}" ,
1888
2014
variables: % { "pattern" => inspect ( pattern ) , "error" => inspect ( error ) } ,
2015
+ send_telemetry: false ,
1889
2016
show_user: true
1890
2017
end
1891
2018
end )
0 commit comments