|
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