-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
The Fanciest REPL History in the Land #59819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Anyone else getting "video playback aborted due to a network error"? |
If possible, it would be nice to cut this up into some orthogonal pieces. For example, the AnnotatedString perf improvements could be a separate PR that (with benchmarks) could be merged and would make the diff here smaller and easier to review. |
stdlib/REPL/src/History/search.jl
Outdated
filename = try | ||
readline(term.in_stream) | ||
catch err | ||
if err isa InterruptException | ||
"" | ||
else | ||
rethrow() | ||
end | ||
end | ||
isempty(filename) && (println(out, S"\e[F\e[2K{light,grey:{bold:history>} {red:×} History selection aborted}\n"); return) | ||
write(filename, "# Julia REPL history excerpt\n\n", content) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it should default write to a location? The prompt could default to ~/.julia/history.jl
(or a more appropriate location).
Ideally, the prompt for the filename would also allow scrolling up and down with the up arrow and down arrow, typing some characters of the file and hitting up arrow to narrow the search, have a ghost text of the last file name or the default file name so right arrow completes it etc. But I can imagine this being awkward the way things are set up in the REPL?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, the prompt for the filename would also allow scrolling up and down with the up arrow and down arrow, typing some characters of the file and hitting up arrow to narrow the search, have a ghost text of the last file name or the default file name so right arrow completes it etc. But I can imagine this being awkward the way things are set up in the REPL?
I've had exactly the same thought. I just can't be bothered to make it happen 😅
I'm happy to split this up, but there are really just three parts to it:
I could split 1-2 off into a separate PR to review, if that sounds like a nice idea?
There's only suspicious performance here, not perf improvements, unfortunately 😞. I say "suspicious" because if I remove the keyword argument from For now, I've left these julia/base/strings/annotated_io.jl Lines 202 to 226 in cc7ed22
julia/base/strings/annotated_io.jl Lines 236 to 240 in cc7ed22
|
cc7ed22
to
75fd56d
Compare
I've just added back ~400 loc of the original code for using up/down arrow keys to go through recent history without If you start a new REPL and immediately press up arrow, it does nothing the first time. Not quite sure why... (any ideas?) I would like to add session-awareness. Maybe I'll try to drop that in this PR too? |
75fd56d
to
221b4e5
Compare
Rebased to the latest REPL Syntax Highlighting |
221b4e5
to
ee23322
Compare
Fixed some typos. |
The precompilation situation is looking pretty decent, this is all I'm seeing with
|
ee23322
to
3a6d8d7
Compare
Rebased now that #59778 has been merged. |
3a6d8d7
to
4bac24f
Compare
Fixed. |
4bac24f
to
c7a66cb
Compare
Thanks to Miguel, Camillo, and Sundar for taking this for a test-drive and providing feedback 🙂 Changes:
|
7126dd7
to
0da2a86
Compare
Rebase (get the REPL precompilation improvements) |
0da2a86
to
2fd2cea
Compare
|
Extract the replacement loop body into `_replace_once` to ease future annotation tracking during string replacement operations. The new function returns match information (pattern index, match range, bytes written) that will be needed to properly adjust annotation positions when replacements occur.
97fd821
to
323f5df
Compare
|
Implement `replace` function for `AnnotatedString` that properly handles annotation regions during pattern replacement operations. The function tracks which bytes are replaced versus preserved, maintaining annotations only on original content and adding new annotations from replacement text. - Supports AnnotatedChar, AnnotatedString, and SubString replacements - Drops, shifts, and splits existing annotations appropriately - Refactored `_insert_annotations!` to work with annotation vectors directly - Adjacent replacements with identical annotations are merged into single regions - Lots of tests (thanks Claude!) Performance is strangely poor. For the test case mentioned in the REVIEW comment within `_insert_annotations!` we should be able to perform the replacement in ~200ns (compared to ~70ns for the equivalent unannotated case). However, for two reasons that are beyond me instead it takes ~4400ns. See the REVIEW comments for more details, help would be much appreciated.
ff425b1
to
fc8f7fb
Compare
|
fc8f7fb
to
548f27d
Compare
|
Since the dawn of the Julia REPL, history completion has been limited to a readline-style interface. OhMyREPL improved the experience with fzf, but those who yearned for a delightful history completion experience (me) were left underwhelmed. With this overhaul, I now find myself spending more time looking through my history because it's just *so nice* to do so. The new history system is organised as a standalone module in stdlib/REPL/src/History with a clear separation of concerns: 1. History file management 2. Event-driven prompt/UI updating 3. Incremental filtering 4. UI display 5. Search coordination (prompt + display + filter) I've attempted to pull out all the (reasonable) stops to make history searching as fluid and snappy as possible. By memory mapping the history file in the initial read, and optimising the parser, we can read ~2 million history items per second. Result filtering is incremental and resumable, performed in dynamically sized batches to ensure responsiveness. Rapid user inputs are debouced. We store a log-structured record of previous search result, and compare search strictness to resume from prior partial results instead of filtering the history from scratch every time. Syncronisation between the interface and filtering is enabled via a Channel-based event loop. Enjoy! (I know I am)
Includes these changes: f5d171019 * Drop the search keymap, removed in Julia 1.13 (#???) 93a960c76 * origin/master Adapt delayed delete mechanism (JuliaLang#4392) 4184c9ba0 * Add ASCII requirement for package naming (JuliaLang#4404)
548f27d
to
74ba1c6
Compare
|
Unit tests are still needed, but I think this PR is well worth trying/reviewing now. |
print(buf, "\eP=1s\e\\") # Start sync update | ||
currentrow = 0 | ||
if newstate.query == FILTER_HELP_QUERY | ||
print(buf, "\e[1G\e[J\n", FILTER_HELPSTRING) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When entering into help mode, currently the input prompt exists but is not displayed. I think it's fine to show the prompt as is:

Users will know to backspace to get out of help then.
Related: what are your thoughts on pulling these control sequences to inline functions:
function redisplay_all(io::IO, oldstate::SelectorState, newstate::SelectorState, pstate::REPL.LineEdit.PromptState;
buf::IOContext{IOBuffer} = IOContext(IOBuffer(), io))
# Calculate dimensions
oldrows = componentrows(oldstate)
newrows = componentrows(newstate)
# Redisplay components
_begin_synchronized_update!(buf)
currentrow = 0
if newstate.query == FILTER_HELP_QUERY
_move_cursor_to_first_column!(buf)
_erase_to_end_of_line!(buf)
print(buf, "\n")
print(buf, FILTER_HELPSTRING)
...
The Fanciest REPL History in the Land ✨
Do you dread typing out code for the second time? Are you a particular enjoyed of REPL history?
Well, I know I am, and for years I have yearned for something better than the current
readline
-style completion, better than OhMyREPL.jl's fzf-driven completion, better than any REPL history I've seen before!It's not quite finished baking, but we're onto the final stretch 😀
repl_history_demo.webm
Thanks to @kdheepak, @jakobnissen, and @digital-carver for helping me design the UI and UX over on Zulip (#repl > Revamped REPL history).
Features
TODO
replace
methodreplace
methodreplace
method (see: theREVIEW: ...
code comments inannotated_io.jl
)This PR is on top of #59778, because I think I can safely assume that will be merged first.