|
4 | 4 | require 'irb/completion' |
5 | 5 | require 'tmpdir' |
6 | 6 | require 'fileutils' |
| 7 | +require_relative 'variable' |
| 8 | +require_relative 'variable_inspector' |
7 | 9 |
|
8 | 10 | module DEBUGGER__ |
9 | 11 | module UI_DAP |
@@ -765,18 +767,11 @@ def register_vars vars, tid |
765 | 767 | end |
766 | 768 | end |
767 | 769 |
|
768 | | - class NaiveString |
769 | | - attr_reader :str |
770 | | - def initialize str |
771 | | - @str = str |
772 | | - end |
773 | | - end |
774 | | - |
775 | 770 | class ThreadClient |
776 | 771 | MAX_LENGTH = 180 |
777 | 772 |
|
778 | 773 | def value_inspect obj, short: true |
779 | | - # TODO: max length should be configuarable? |
| 774 | + # TODO: max length should be configurable? |
780 | 775 | str = DEBUGGER__.safe_inspect obj, short: short, max_length: MAX_LENGTH |
781 | 776 |
|
782 | 777 | if str.encoding == Encoding::UTF_8 |
@@ -867,56 +862,28 @@ def process_dap args |
867 | 862 | fid = args.shift |
868 | 863 | frame = get_frame(fid) |
869 | 864 | vars = collect_locals(frame).map do |var, val| |
870 | | - variable(var, val) |
| 865 | + render_variable Variable.new(name: var, value: val) |
871 | 866 | end |
872 | 867 |
|
873 | 868 | event! :protocol_result, :scope, req, variables: vars, tid: self.id |
874 | 869 | when :variable |
875 | 870 | vid = args.shift |
876 | | - obj = @var_map[vid] |
877 | | - if obj |
878 | | - case req.dig('arguments', 'filter') |
879 | | - when 'indexed' |
880 | | - start = req.dig('arguments', 'start') || 0 |
881 | | - count = req.dig('arguments', 'count') || obj.size |
882 | | - vars = (start ... (start + count)).map{|i| |
883 | | - variable(i.to_s, obj[i]) |
884 | | - } |
885 | | - else |
886 | | - vars = [] |
887 | 871 |
|
888 | | - case obj |
889 | | - when Hash |
890 | | - vars = obj.map{|k, v| |
891 | | - variable(value_inspect(k), v,) |
892 | | - } |
893 | | - when Struct |
894 | | - vars = obj.members.map{|m| |
895 | | - variable(m, obj[m]) |
896 | | - } |
897 | | - when String |
898 | | - vars = [ |
899 | | - variable('#length', obj.length), |
900 | | - variable('#encoding', obj.encoding), |
901 | | - ] |
902 | | - printed_str = value_inspect(obj) |
903 | | - vars << variable('#dump', NaiveString.new(obj)) if printed_str.end_with?('...') |
904 | | - when Class, Module |
905 | | - vars << variable('%ancestors', obj.ancestors[1..]) |
906 | | - when Range |
907 | | - vars = [ |
908 | | - variable('#begin', obj.begin), |
909 | | - variable('#end', obj.end), |
910 | | - ] |
911 | | - end |
| 872 | + if @var_map.has_key?(vid) |
| 873 | + obj = @var_map[vid] |
912 | 874 |
|
913 | | - unless NaiveString === obj |
914 | | - vars += M_INSTANCE_VARIABLES.bind_call(obj).sort.map{|iv| |
915 | | - variable(iv, M_INSTANCE_VARIABLE_GET.bind_call(obj, iv)) |
916 | | - } |
917 | | - vars.unshift variable('#class', M_CLASS.bind_call(obj)) |
918 | | - end |
| 875 | + members = case req.dig('arguments', 'filter') |
| 876 | + when 'indexed' |
| 877 | + VariableInspector.new.indexed_members_of( |
| 878 | + obj, |
| 879 | + start: req.dig('arguments', 'start') || 0, |
| 880 | + count: req.dig('arguments', 'count') || obj.size, |
| 881 | + ) |
| 882 | + else |
| 883 | + VariableInspector.new.named_members_of(obj) |
919 | 884 | end |
| 885 | + |
| 886 | + vars = members.map { |member| render_variable member } |
920 | 887 | end |
921 | 888 | event! :protocol_result, :variable, req, variables: (vars || []), tid: self.id |
922 | 889 |
|
@@ -973,7 +940,13 @@ def process_dap args |
973 | 940 | result = 'Error: Can not evaluate on this frame' |
974 | 941 | end |
975 | 942 |
|
976 | | - event! :protocol_result, :evaluate, req, message: message, tid: self.id, **evaluate_result(result) |
| 943 | + result_variable = Variable.new(name: nil, value: result) |
| 944 | + |
| 945 | + event! :protocol_result, :evaluate, req, |
| 946 | + message: message, |
| 947 | + tid: self.id, |
| 948 | + result: result_variable.inspect_value, |
| 949 | + **render_variable(result_variable) |
977 | 950 |
|
978 | 951 | when :completions |
979 | 952 | fid, text = args |
@@ -1035,72 +1008,54 @@ def search_const b, expr |
1035 | 1008 | false |
1036 | 1009 | end |
1037 | 1010 |
|
1038 | | - def evaluate_result r |
1039 | | - variable nil, r |
1040 | | - end |
| 1011 | + # Renders the given Member into a DAP Variable |
| 1012 | + # https://microsoft.github.io/debug-adapter-protocol/specification#variable |
| 1013 | + def render_variable member |
| 1014 | + indexedVariables, namedVariables = if Array === member.value |
| 1015 | + [member.value.size, 0] |
| 1016 | + else |
| 1017 | + [0, VariableInspector.new.named_members_of(member.value).count] |
| 1018 | + end |
1041 | 1019 |
|
1042 | | - def type_name obj |
1043 | | - klass = M_CLASS.bind_call(obj) |
1044 | 1020 |
|
1045 | | - begin |
1046 | | - M_NAME.bind_call(klass) || klass.to_s |
1047 | | - rescue Exception => e |
1048 | | - "<Error: #{e.message} (#{e.backtrace.first}>" |
| 1021 | + if member.value == false || member.value == true |
| 1022 | + require "awesome_print" |
| 1023 | + ap({ member:, indexedVariables:, namedVariables: }) |
1049 | 1024 | end |
1050 | | - end |
1051 | 1025 |
|
1052 | | - def variable_ name, obj, indexedVariables: 0, namedVariables: 0 |
| 1026 | + # > If `variablesReference` is > 0, the variable is structured and its children |
| 1027 | + # > can be retrieved by passing `variablesReference` to the `variables` request |
| 1028 | + # > as long as execution remains suspended. |
1053 | 1029 | if indexedVariables > 0 || namedVariables > 0 |
| 1030 | + # This object has children that we might need to query, so we need to remember it by its vid |
1054 | 1031 | vid = @var_map.size + 1 |
1055 | | - @var_map[vid] = obj |
| 1032 | + @var_map[vid] = member.value |
1056 | 1033 | else |
| 1034 | + # This object has no children, so we don't need to remember it in the `@var_map` |
1057 | 1035 | vid = 0 |
1058 | 1036 | end |
1059 | 1037 |
|
1060 | | - namedVariables += M_INSTANCE_VARIABLES.bind_call(obj).size |
1061 | | - |
1062 | | - if NaiveString === obj |
1063 | | - str = obj.str.dump |
1064 | | - vid = indexedVariables = namedVariables = 0 |
1065 | | - else |
1066 | | - str = value_inspect(obj) |
1067 | | - end |
1068 | | - |
1069 | | - if name |
1070 | | - { name: name, |
1071 | | - value: str, |
1072 | | - type: type_name(obj), |
| 1038 | + variable = if member.name |
| 1039 | + # These two hashes are repeated so the "name" can come always come first, when available, |
| 1040 | + # which improves the readability of protocol responses. |
| 1041 | + { |
| 1042 | + name: member.name, |
| 1043 | + value: member.inspect_value, |
| 1044 | + type: member.value_type_name, |
1073 | 1045 | variablesReference: vid, |
1074 | | - indexedVariables: indexedVariables, |
1075 | | - namedVariables: namedVariables, |
1076 | 1046 | } |
1077 | 1047 | else |
1078 | | - { result: str, |
1079 | | - type: type_name(obj), |
| 1048 | + { |
| 1049 | + value: member.inspect_value, |
| 1050 | + type: member.value_type_name, |
1080 | 1051 | variablesReference: vid, |
1081 | | - indexedVariables: indexedVariables, |
1082 | | - namedVariables: namedVariables, |
1083 | 1052 | } |
1084 | 1053 | end |
1085 | | - end |
1086 | 1054 |
|
1087 | | - def variable name, obj |
1088 | | - case obj |
1089 | | - when Array |
1090 | | - variable_ name, obj, indexedVariables: obj.size |
1091 | | - when Hash |
1092 | | - variable_ name, obj, namedVariables: obj.size |
1093 | | - when String |
1094 | | - variable_ name, obj, namedVariables: 3 # #length, #encoding, #to_str |
1095 | | - when Struct |
1096 | | - variable_ name, obj, namedVariables: obj.size |
1097 | | - when Class, Module |
1098 | | - variable_ name, obj, namedVariables: 1 # %ancestors (#ancestors without self) |
1099 | | - when Range |
1100 | | - variable_ name, obj, namedVariables: 2 # #begin, #end |
1101 | | - else |
1102 | | - variable_ name, obj, namedVariables: 1 # #class |
1103 | | - end |
| 1055 | + variable[:indexedVariables] = indexedVariables unless indexedVariables == 0 |
| 1056 | + variable[:namedVariables] = namedVariables unless namedVariables == 0 |
| 1057 | + |
| 1058 | + variable |
1104 | 1059 | end |
1105 | 1060 | end |
1106 | 1061 | end |
0 commit comments