Comments (8)
Oh wait, there's Rope::split_off()
and Rope::append()
!
from ropey.
(While I'm at it, are you considering WeakRope
s for v2?)
from ropey.
I'm not sure what you mean by WeakRope
. Can you elaborate?
My use case: editor's copy/paste/edit when selection is "big".
Am I approaching this right? How much bytes/chunks would "big" be to see benefits over inserting in a loop?
I did some quick tests on my machine. Keep in mind that these are just to give a rough idea, because all the tests started with an empty rope. But I think the numbers should be in the right ball park. All tests progressively insert the insertion text in a loop, 500 bytes at a time.
- 10 MB of text takes around 10 milliseconds. That would be imperceptible to a user for an operation like copy/paste.
- 100 MB of text takes about 150 milliseconds, which I doubt would bother anyone when copy/pasting.
- 1 GB of text takes about 1.5 seconds. This would definitely be annoying without any UI feedback to let you know what's going on (and perhaps a way to cancel it).
So I'd say as long as you aren't expecting your users to regularly paste more than 100 MB of text, it probably doesn't matter much.
Also, my personal opinion on this is that since copy/paste can also happen from e.g. the system clipboard, where you can't optimize with split/append anyway, it's better to focus on making sure the UI remains responsive during long operations if you're worried about copy/pasting text that large. You can't guarantee where that text data is coming from, and ideally the user experience should be good regardless.
from ropey.
Hello,
I'm not sure what you mean by WeakRope. Can you elaborate?
pub struct WeakRope {
pub(crate) root: std::sync::Weak<Node>,
}
So I can:
/// A `(index , line, column, width)` cursor.
///
/// Values for `line`, `column` and `width` are cached
/// and recomputed only if [`Rope::is_instance()`] is `false`.
#[derive(Default)]
pub struct CachedCursor {
index: usize,
line: Cell<Option<usize>>,
column: Cell<Option<usize>>,
width: Cell<Option<usize>>,
rope: Cell<WeakRope>,
}
(I'm probably over engineering this) (see)
I did some quick tests on my machine.
Not sure I understand. rope.internal_insert(random_index, some_str)
?
I use 6 * MAX_BYTES
for "big" because of this comment, but anyway you are right it shouldn't matter that much for usual cases.
Thanks for your answer!
from ropey.
pub struct WeakRope { pub(crate) root: std::sync::Weak<Node>, }
Ah, got it. I have no plans to add support for anything like that to Ropey, no. To be honest, I kind of regret adding the is_instance()
method as well, and I likely won't be reproducing it in Ropey 2 unless someone can make a very compelling argument for it. Rope clones in Ropey are supposed to have full copy semantics: semantically they have nothing to do with each other from the moment of creation. They just happen to be abnormally efficient in terms of time and space.
Instance/reference semantics can still be built on top of Ropey, the same way you would build them on top of any other type. For example, by simply wrapping them in an Arc
yourself.
from ropey.
Not sure I understand.
rope.internal_insert(random_index, some_str)
?
Ah, no, I mean just calling rope.insert()
in a loop, with 500 bytes of text at a time. You were asking about optimizing text copy/paste by tree splicing (split_off()
and append()
) vs just directly inserting the text. If you were trying to paste via directly inserting from another rope or rope slice, that would mean looping over their chunks and inserting them one at a time. I was trying to roughly emulate that.
For me the bigger issue, though, is simply that specifically optimizing for copy/paste from within the application seems odd. At least, when I'm using a text editor, a fair bit of the copy/pasting I do actually comes from sources outside the editor. So IMO special-casing your copy/paste code for internal copy/pastes doesn't seem worth it...? But maybe I'm missing something.
from ropey.
I have no plans to add support for anything like that to Ropey, no. To be honest, I kind of regret adding the is_instance() method as well, and I likely won't be reproducing it in Ropey 2 unless someone can make a very compelling argument for it.
😭. I hope someone has a good argument! I don't want to deal with Arc<RefCell<Rope>>
(god forbid, Arc<Mutex<Rope>>
).
I mean just calling rope.insert() in a loop
Ah ok, I though you were talking about benches you previously did. Thanks, by the way!
I'll keep my breakpoint at 6 * MAX_BYTES
then.
the copy/pasting I do actually comes from sources outside the editor [...] But maybe I'm missing something.
Wow, I almost never do that.
I actually want to optimise space by storing ropes in the undo/redo stack (when "big"). Optimising time is a bonus on top of that.
Thanks
from ropey.
I don't want to deal with Arc<RefCell> (god forbid, Arc<Mutex>).
I doubt you'll need to. I don't mean this with any disrespect (I'm often known to just go for the easy solutions myself at times), but I think most if not all of the use cases people have for is_instance()
in Ropey is due to not really thinking out what they really need.
For example, a common use case is to make a clone to do processing in a different thread, but then cheaply check if the original rope changed before utilizing the result of the processing, to make sure it's not stale. But that can be done just as cheaply (and with no need for Arc
etc.) with a simple counter that accompanies the rope and increments whenever an edit is made.
Also, keep in mind that I have no plans to stop maintenance of Ropey 1.x even after 2.x is out. It will only be for bug fixes, no new features, but in practice that's been the case for a long time already, because it's effectively feature complete. In other words, if you're happy with 1.x then there's no reason you'll need to move to 2.x. Part of the goal of 2.x is to be a leaner library with a smaller API, so I'm sure some people will choose to stick with 1.x for that reason, and that's totally fine.
I actually want to optimise space by storing ropes in the undo/redo stack (when "big"). Optimising time is a bonus on top of that.
If you're trying to go that far into optimizing in ways that need deeper insight/control over the fundamental text data structure you use, I would actually recommend rolling your own rather than using Ropey or any other third party library. I'm reminded of this talk by John Carmack. At some point, to fully optimize a system, you need close to full control over all the components. Ropey can't reasonably be optimal for all use cases and text editor architectures.
And if you're writing a data structure just for your editor, you can actually get it up and running much faster than writing a library, because you only have to write the parts your editor actually needs. You could also explore something like a piece table, which might be more efficient/natural than a rope for the kinds of optimizations it sounds like you want to do.
from ropey.
Related Issues (20)
- Insert to another rope HOT 4
- Performance issue with the redundancy operations HOT 1
- `ropey` doesn't agree with `wc` HOT 7
- Async IO support for `Rope`? HOT 1
- Chunks iterator get's confused when you change direction twice. HOT 5
- test case failed lines_exact_size_iter_04 HOT 1
- attempt to compute `0_usize - 1_usize`, which would overflow HOT 2
- RopeBuilder's Default derive creates an invalid RopeBuilder HOT 1
- `TextInfo` in `Chunks` API HOT 11
- subtract with overflow in new line iterator HOT 4
- Comparaison with Xi editor HOT 1
- Is it okay if I publish a fork of this crate that works with any type of data? HOT 3
- peek methods on iterators. HOT 3
- [Qustion]: How to get the col number of byte index HOT 1
- Lines iterated ropey is ~2x slower when highlighting ~1k lines of code than a simple Vec of Vec of chars HOT 1
- Rope Graphemes Example HOT 1
- Tests and `debug_assert!` HOT 2
- Test `pt_shrink_to_fit_01` fails on i686 HOT 14
- Chars::reversed not working as expected HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ropey.