1
1
__precompile__ ()
2
2
module DebuggerFramework
3
+ include (" LineNumbers.jl" )
4
+ using LineNumbers: SourceFile, compute_line
5
+
3
6
abstract type StackFrame end
4
7
5
8
function print_var (io:: IO , name, val:: Nullable , undef_callback)
@@ -41,6 +44,16 @@ module DebuggerFramework
41
44
return false
42
45
end
43
46
47
+ function execute_command (state, frame, :: Val{Symbol("?")} , cmd)
48
+ println (" Help not implemented for this debugger." )
49
+ return false
50
+ end
51
+
52
+ function execute_command (state, frame, _, cmd)
53
+ println (" Unknown command `$cmd `. Executing `?` to obtain help." )
54
+ execute_command (state, frame, Val {Symbol("?")} (), " ?" )
55
+ end
56
+
44
57
function execute_command (state, interp, :: Union{Val{:f},Val{:fr}} , command)
45
58
subcmds = split (command,' ' )[2 : end ]
46
59
if isempty (subcmds) || subcmds[1 ] == " v"
@@ -69,24 +82,100 @@ module DebuggerFramework
69
82
mutable struct DebuggerState
70
83
stack
71
84
level
85
+ repl
72
86
main_mode
87
+ language_modes
88
+ standard_keymap
73
89
terminal
74
90
end
91
+ dummy_state (stack) = DebuggerState (stack, 1 , nothing , nothing , nothing , nothing , nothing )
75
92
76
93
function print_status_synthtic (io, state, frame, lines_before, total_lines)
77
94
return 0
78
95
end
79
96
80
- haslocinfo (frame) = false
97
+ struct FileLocInfo
98
+ filepath:: String
99
+ line:: Int
100
+ # 0 if unknown
101
+ column:: Int
102
+ # The line at which the current context starts, 0 if unknown
103
+ defline:: Int
104
+ end
105
+
106
+ struct BufferLocInfo
107
+ data:: String
108
+ line:: Int
109
+ # 0 if unknown
110
+ column:: Int
111
+ defline:: Int
112
+ end
113
+
114
+ locinfo (frame) = nothing
81
115
locdesc (frame) = " unknown function"
82
116
117
+ """
118
+ Determine the offsets in the source code to print, based on the offset of the
119
+ currently highlighted part of the code, and the start and stop line of the
120
+ entire function.
121
+ """
122
+ function compute_source_offsets (code, offset, startline, stopline; file = SourceFile (code))
123
+ offsetline = compute_line (file, offset)
124
+ if offsetline - 3 > length (file. offsets) || startline > length (file. offsets)
125
+ return - 1 , - 1
126
+ end
127
+ startoffset = max (file. offsets[max (offsetline- 3 ,1 )], file. offsets[startline])
128
+ stopoffset = endof (code)- 1
129
+ if offsetline + 3 < endof (file. offsets)
130
+ stopoffset = min (stopoffset, file. offsets[offsetline + 3 ]- 1 )
131
+ end
132
+ if stopline + 1 < endof (file. offsets)
133
+ stopoffset = min (stopoffset, file. offsets[stopline + 1 ]- 1 )
134
+ end
135
+ startoffset, stopoffset
136
+ end
137
+
138
+ function print_sourcecode (io, code, line, defline; file = SourceFile (code))
139
+ startoffset, stopoffset = compute_source_offsets (code, file. offsets[line], defline, line+ 3 ; file= file)
140
+
141
+ if startoffset == - 1
142
+ print_with_color (:bold , io, " Line out of file range (bad debug info?)" )
143
+ return
144
+ end
145
+
146
+ # Compute necessary data for line numbering
147
+ startline = compute_line (file, startoffset)
148
+ stopline = compute_line (file, stopoffset)
149
+ current_line = line
150
+ stoplinelength = length (string (stopline))
151
+
152
+ code = split (code[(startoffset: stopoffset)+ 1 ],' \n ' )
153
+ lineno = startline
154
+
155
+ if ! isempty (code) && isempty (code[end ])
156
+ pop! (code)
157
+ end
158
+
159
+ for textline in code
160
+ print_with_color (lineno == current_line ? :yellow : :bold , io,
161
+ string (lineno, " " ^ (stoplinelength- length (lineno)+ 1 )))
162
+ println (io, textline)
163
+ lineno += 1
164
+ end
165
+ println (io)
166
+ end
167
+
168
+ print_next_state (outbuf:: IO , state, frame) = nothing
169
+
83
170
print_status (io, state) = print_status (io, state, state. stack[state. level])
84
171
function print_status (io, state, frame)
85
172
# Buffer to avoid flickering
86
173
outbuf = IOBuffer ()
87
174
print_with_color (:bold , outbuf, " In " , locdesc (frame), " \n " )
88
- if haslocinfo (frame)
89
- # Print location here
175
+ loc = locinfo (frame)
176
+ if loc != = nothing
177
+ print_sourcecode (outbuf, isa (loc, BufferLocInfo) ? loc. data : readstring (loc. filepath),
178
+ loc. line, loc. defline)
90
179
else
91
180
buf = IOBuffer ()
92
181
active_line = print_status_synthtic (buf, state, frame, 2 , 5 ):: Int
@@ -100,6 +189,7 @@ module DebuggerFramework
100
189
end
101
190
end
102
191
end
192
+ print_next_state (outbuf, state, frame)
103
193
print (io, String (take! (outbuf)))
104
194
end
105
195
@@ -108,22 +198,35 @@ module DebuggerFramework
108
198
function execute_command
109
199
end
110
200
201
+ function language_specific_prompt
202
+ end
203
+
204
+ function eval_code (state, frame, code)
205
+ error (" Code evaluation not implemented for this debugger" )
206
+ end
207
+
208
+ function eval_code (state, code)
209
+ try
210
+ result = eval_code (state, state. stack[1 ], code)
211
+ true , result
212
+ catch err
213
+ bt = catch_backtrace ()
214
+ false , (err, bt)
215
+ end
216
+ end
217
+
111
218
using Base: LineEdit, REPL
219
+ promptname (level, name) = " $level |$name > "
112
220
function RunDebugger (stack, repl = Base. active_repl, terminal = Base. active_repl. t)
113
- promptname (level, name) = " $level |$name > "
114
221
115
- state = DebuggerState (stack, 1 , nothing , terminal)
222
+ state = DebuggerState (stack, 1 , repl, nothing , Dict {Symbol, Any} (), nothing , terminal)
116
223
117
224
# Setup debug panel
118
225
panel = LineEdit. Prompt (promptname (state. level, " debug" );
119
226
prompt_prefix= " \e [38;5;166m" ,
120
227
prompt_suffix= Base. text_colors[:white ],
121
228
on_enter = s-> true )
122
229
123
- # For now use the regular REPL completion provider
124
- replc = Base. REPL. REPLCompletionProvider ()
125
-
126
-
127
230
panel. hist = REPL. REPLHistoryProvider (Dict {Symbol,Any} (:debug => panel))
128
231
Base. REPL. history_reset_state (panel. hist)
129
232
@@ -181,13 +284,10 @@ module DebuggerFramework
181
284
return true
182
285
end
183
286
184
- const all_commands = (" q" , " s" , " si" , " finish" , " bt" , " loc" , " ind" , " shadow" ,
185
- " up" , " down" , " ns" , " nc" , " n" , " se" )
186
-
187
287
const repl_switch = Dict {Any,Any} (
188
288
' `' => function (s,args... )
189
289
if isempty (s) || position (LineEdit. buffer (s)) == 0
190
- prompt = language_specific_prompt (state, state. interp )
290
+ prompt = language_specific_prompt (state, state. stack[ 1 ] )
191
291
buf = copy (LineEdit. buffer (s))
192
292
LineEdit. transition (s, prompt) do
193
293
LineEdit. state (s, prompt). input_buffer = buf
@@ -198,8 +298,8 @@ module DebuggerFramework
198
298
end
199
299
)
200
300
201
- b = Dict{Any,Any}[skeymap, LineEdit. history_keymap, LineEdit. default_keymap, LineEdit. escape_defaults]
202
- panel. keymap_dict = LineEdit. keymap ([repl_switch;b ])
301
+ state . standard_keymap = Dict{Any,Any}[skeymap, LineEdit. history_keymap, LineEdit. default_keymap, LineEdit. escape_defaults]
302
+ panel. keymap_dict = LineEdit. keymap ([repl_switch;state . standard_keymap ])
203
303
204
304
# Skip evaluated values (e.g. constants)
205
305
print_status (Base. pipe_writer (terminal), state)
0 commit comments