ajaxorg / ace

Ace (Ajax.org Cloud9 Editor)
https://ace.c9.io
Other
26.72k stars 5.28k forks source link

Sticky Scroll #5341

Open mmackh opened 1 year ago

mmackh commented 1 year ago

Describe the feature

Sticky scroll is the name for the feature in VSCode that automatically pins the current function to the top of the editor and allows you to see context during editing. More details here.

n6sd44eq7y9076tin6dl ubddgg3wzr6mzikeg6rr

Use Case

Improved editing due to context awareness.

Proposed Solution

No response

Other Information

No response

Acknowledgements

ACE version used

1.28

mmackh commented 1 year ago

I have come up with a basic idea on how this could work:

1) observe scroll position 2) look at all the collapsible lines before it, this will give a pretty good estimation of the code structure 3) draw the lines in a separate container on top of the editor

There are 0 performance optimisations, missing line numbers, and this doesn't do any animation, etc. but here's some code I came up with:

<div id="context" class="ace_editor ace_layer" style="position: fixed; left: 0; top: 0; z-index: 10; "></div>
<pre id="editor">

</pre>
   editor.session.on("changeScrollTop", function(scrollTop) {  
        var firstVisibleRow = editor.getFirstVisibleRow();
      updateStickyScrollForCurrentRow(firstVisibleRow);
    });

    var isFoldStructureIncrementing = false;
    var previousFoldStructure = [];
    function updateStickyScrollForCurrentRow(row) {
        var session = editor.session;
        var foldWidgets = session.foldWidgets;
        var foldStructure = [];

        var length = previousFoldStructure.length;

        var startRow = row + length;
        var endRow = row + length + (isFoldStructureIncrementing ? 0 : 1);

        for (var i = 0; i <= startRow; i += 1) {
            if (foldWidgets[i] == "") continue;

            var range = session.getFoldWidgetRange(i);
            if (!range) continue;

            var start = range.start.row;
            var end = range.end.row;

            if (startRow >= start && endRow < end) {
                //renderLine(i);
                foldStructure.push(renderLine(i).outerHTML);
            }
        }

        context.innerHTML = foldStructure.join("");

        let newLength = foldStructure.length;
        if (newLength < length) {
            isFoldStructureIncrementing = false;
        } else if (newLength > length) {
            isFoldStructureIncrementing = true;
        }

        previousFoldStructure = foldStructure;
    }

    function renderLine(row) {
            var textLayer = editor.renderer.$textLayer;
            var height = document.querySelector('.ace_line_group').style.height;

            var lineDiv = document.createElement("div");
            lineDiv.classList.add('ace_line');
            lineDiv.style.height = height + 'px';

            var tokens = editor.session.getTokens(row);

            textLayer.$renderSimpleLine(lineDiv, tokens);
            return lineDiv;
        }
khaven commented 8 months ago

Hi, Since you are working on a scroll feature, if it is possible, could you please look at this issue too?

https://github.com/ajaxorg/ace/issues/5292

Other online code editors don't have this issue when scrolling.

TimChinye commented 4 months ago

Just a quick update on the fr: I'd really love to have this.

If there's no official extension by the time I get to releasing v1 of my current project, I'll do it.

TimChinye commented 4 months ago

Just a quick update on the fr: I'd really love to have this.

If it's still on the back burner by the time I get to releasing v1 of my current project, I'll attempt to implement it myself.

My use-case is explicitly for the new CSS nesting

Update:

I woke up the next day and realised that implementation would actually be pretty simple, so I spent a couple hours on it. And, it works, pretty well. The only issue is I made it for my project and there could be some logical improvements, so for it to be an ace extension everyone can use, it'll need a bit of tinkering.

I'll provide the code, might be useful for someone else to officially implement into Ace: https://pastecode.io/s/6g7qj98k

Missing features:

That's what I'm using for now, as mentioned in the previous comment, I'll make an official ace extension sometime later.

Preview of what the code I linked above does to my editor: VideoCapture

TimChinye commented 4 months ago

The issue with the code above is that the top of code is underneath the sticky lines, as opposed to beneath it... which means you can like edit and select text underneath the sticky lines, as thus you can't see what you're doing but also since the top of the code is defined in an area you can't see, you can get situations like this: image

Becoming this: image

The following code is a fix to that, but in order to do so, I introduced another bug as I had to add filler lines in order to update content's height, without resize the editor itself (as that'd cause a jittery effect when scrolling). Which means, if you select all the code, you will also select that bottom part when copying, you can else edit the bottom part.

I imagine is also possible to just move the cursor back to a place where I can be seen in the editor, and perhaps a way to edit the selected text, if so, that would fix this bug for now, that's the caveat, here's the current code: https://pastecode.io/s/k5gjtoj2

nightwing commented 4 months ago

What principle do we use to determine which lines to show as sticky? is it simply all the lines with fold widgets that when collapsed would hide the top line in editor?

I wonder if in such case we could implement this as a kind of dynamic fold.

TimChinye commented 4 months ago

What principle do we use to determine which lines to show as sticky? is it simply all the lines with fold widgets that when collapsed would hide the top line in editor?

I wonder if in such case we could implement this as a kind of dynamic fold.

What determines a line to be shown as sticky isn't the same as what determines a line to be foldable.

For instance, that would means comments would be sticky: image

And even strings? (this screenshot is from Monaco Editor, not Ace): image

What determines an element to be sticky, is probably language-dependant, so perhaps this should be a feature of the modes.

- <div class="ace_line"></div>
+ <div class="ace_line ace_sticky"></div>