Skip to content

Commit 8eb55ab

Browse files
KristofferCtkelman
authored andcommitted
RFC: jump to numbered stackframe with hotkey (#19680)
* jump to numbered stackframe with hotkey CTRL+Q * fix grammar * add pr ref to NEWS
1 parent 7eadb55 commit 8eb55ab

File tree

4 files changed

+64
-32
lines changed

4 files changed

+64
-32
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ Library improvements
8282

8383
* The `chop` and `chomp` functions now return a `SubString` ([#18339]).
8484

85+
* Numbered stackframes printed in stacktraces can be opened in an editor by entering the corresponding number in the REPL and pressing `^Q` ([#19680]).
86+
8587
* The REPL now supports something called *prompt pasting* ([#17599]).
8688
This activates when pasting text that starts with `julia> ` into the REPL.
8789
In that case, only expressions starting with `julia> ` are parsed, the rest are removed.
@@ -801,4 +803,5 @@ Language tooling improvements
801803
[#19543]: https://github.com/JuliaLang/julia/issues/19543
802804
[#19598]: https://github.com/JuliaLang/julia/issues/19598
803805
[#19635]: https://github.com/JuliaLang/julia/issues/19635
806+
[#19680]: https://github.com/JuliaLang/julia/issues/19680
804807
[#19787]: https://github.com/JuliaLang/julia/issues/19787

base/REPL.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,26 @@ function setup_interface(repl::LineEditREPL; hascolor = repl.hascolor, extra_rep
899899
firstline = false
900900
end
901901
end,
902+
903+
# Open the editor at the location of a stackframe
904+
# This is accessing a global variable that gets set in
905+
# the show_backtrace function.
906+
"^Q" => (s, o...) -> begin
907+
linfos = Base.LAST_BACKTRACE_LINE_INFOS
908+
str = String(take!(LineEdit.buffer(s)))
909+
n = tryparse(Int, str)
910+
isnull(n) && @goto writeback
911+
n = get(n)
912+
if n <= 0 || n > length(linfos) || startswith(linfos[n][1], "./REPL")
913+
@goto writeback
914+
end
915+
Base.edit(linfos[n][1], linfos[n][2])
916+
Base.LineEdit.refresh_line(s)
917+
return
918+
@label writeback
919+
write(Base.LineEdit.buffer(s), str)
920+
return
921+
end,
902922
)
903923

904924
prefix_prompt, prefix_keymap = LineEdit.setup_prefix_keymap(hp, julia_prompt)

base/replutil.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,14 +585,21 @@ function show_trace_entry(io, frame, n; prefix = " in ")
585585
n > 1 && print(io, " (repeats ", n, " times)")
586586
end
587587

588+
# Contains file name and file number. Gets set when a backtrace
589+
# is shown. Used by the REPL to make it possible to open
590+
# the location of a stackframe in the edítor.
591+
global LAST_BACKTRACE_LINE_INFOS = Tuple{String, Int}[]
592+
588593
function show_backtrace(io::IO, t::Vector)
589594
n_frames = 0
590595
frame_counter = 0
596+
resize!(LAST_BACKTRACE_LINE_INFOS, 0)
591597
process_backtrace((a,b) -> n_frames += 1, t)
592598
n_frames != 0 && print(io, "\nStacktrace:")
593599
process_entry = (last_frame, n) -> begin
594600
frame_counter += 1
595601
show_trace_entry(io, last_frame, n, prefix = string(" [", frame_counter, "] "))
602+
push!(LAST_BACKTRACE_LINE_INFOS, (string(last_frame.file), last_frame.line))
596603
end
597604
process_backtrace(process_entry, t)
598605
end

doc/src/manual/interacting-with-julia.md

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -129,38 +129,40 @@ control-key, there are also meta-key bindings. These vary more by platform, but
129129
default to using alt- or option- held down with a key to send the meta-key (or can be configured
130130
to do so).
131131

132-
| Keybinding | Description |
133-
|:------------------- |:---------------------------------------------------------------------------- |
134-
| **Program control** |   |
135-
| `^D` | Exit (when buffer is empty) |
136-
| `^C` | Interrupt or cancel |
137-
| `^L` | Clear console screen |
138-
| Return/Enter, `^J` | New line, executing if it is complete |
139-
| meta-Return/Enter | Insert new line without executing it |
140-
| `?` or `;` | Enter help or shell mode (when at start of a line) |
141-
| `^R`, `^S` | Incremental history search, described above |
142-
| **Cursor movement** |   |
143-
| Right arrow, `^F` | Move right one character |
144-
| Left arrow, `^B` | Move left one character |
145-
| Home, `^A` | Move to beginning of line |
146-
| End, `^E` | Move to end of line |
147-
| `^P` | Change to the previous or next history entry |
148-
| `^N` | Change to the next history entry |
149-
| Up arrow | Move up one line (or to the previous history entry) |
150-
| Down arrow | Move down one line (or to the next history entry) |
151-
| Page-up | Change to the previous history entry that matches the text before the cursor |
152-
| Page-down | Change to the next history entry that matches the text before the cursor |
153-
| `meta-F` | Move right one word |
154-
| `meta-B` | Move left one word |
155-
| **Editing** |   |
156-
| Backspace, `^H` | Delete the previous character |
157-
| Delete, `^D` | Forward delete one character (when buffer has text) |
158-
| meta-Backspace | Delete the previous word |
159-
| `meta-D` | Forward delete the next word |
160-
| `^W` | Delete previous text up to the nearest whitespace |
161-
| `^K` | "Kill" to end of line, placing the text in a buffer |
162-
| `^Y` | "Yank" insert the text from the kill buffer |
163-
| `^T` | Transpose the characters about the cursor |
132+
| Keybinding | Description |
133+
|:------------------- |:-------------------------------------------------------------------------------- |
134+
| **Program control** |   |
135+
| `^D` | Exit (when buffer is empty) |
136+
| `^C` | Interrupt or cancel |
137+
| `^L` | Clear console screen |
138+
| Return/Enter, `^J` | New line, executing if it is complete |
139+
| meta-Return/Enter | Insert new line without executing it |
140+
| `?` or `;` | Enter help or shell mode (when at start of a line) |
141+
| `^R`, `^S` | Incremental history search, described above |
142+
| **Cursor movement** |   |
143+
| Right arrow, `^F` | Move right one character |
144+
| Left arrow, `^B` | Move left one character |
145+
| Home, `^A` | Move to beginning of line |
146+
| End, `^E` | Move to end of line |
147+
| `^P` | Change to the previous or next history entry |
148+
| `^N` | Change to the next history entry |
149+
| Up arrow | Move up one line (or to the previous history entry) |
150+
| Down arrow | Move down one line (or to the next history entry) |
151+
| Page-up | Change to the previous history entry that matches the text before the cursor |
152+
| Page-down | Change to the next history entry that matches the text before the cursor |
153+
| `meta-F` | Move right one word |
154+
| `meta-B` | Move left one word |
155+
| **Editing** |   |
156+
| Backspace, `^H` | Delete the previous character |
157+
| Delete, `^D` | Forward delete one character (when buffer has text) |
158+
| meta-Backspace | Delete the previous word |
159+
| `meta-D` | Forward delete the next word |
160+
| `^W` | Delete previous text up to the nearest whitespace |
161+
| `^K` | "Kill" to end of line, placing the text in a buffer |
162+
| `^Y` | "Yank" insert the text from the kill buffer |
163+
| `^T` | Transpose the characters about the cursor |
164+
| `^Q` | Write a number in REPL and press `^Q` to open editor at corresponding stackframe |
165+
164166

165167
### Customizing keybindings
166168

0 commit comments

Comments
 (0)